diff --git a/README.md b/README.md index 4aa1132..4eab7c8 100644 --- a/README.md +++ b/README.md @@ -13,13 +13,12 @@ Features (mostly untested) * Block template / job manager * Optimized generation transaction building * Process share submissions +* Supports algos: scrypt, scrypt-jane, quark #### To do +* Proof-of-stake support * Payment processing module -* Support more algos (scrypt, scrypt-jane, quark) - * Port [scrypt hash](https://github.com/Tydus/litecoin_scrypt) to node module - * Port [scrypt-jane hash](https://github.com/Rav3nPL/p2pool-yac/tree/master/yac_scrypt) to node module - * Port [quark hash](https://github.com/Neisklar/quarkcoin-hash-python) to node module +* Vardiff * Statistics module * Integrate with PostgreSQL database * Web frontend @@ -32,6 +31,7 @@ Requirements * PostgreSQL * npm dependencies * [scrypt256-hash](https://github.com/zone117x/node-scrypt256-hash) + * [scrypt-jane-hash](https://github.com/zone117x/node-scrypt-jane-hash) * [quark-hash](https://github.com/zone117x/node-quark-hash) * [binpack](https://github.com/russellmcc/node-binpack) * [bignum](https://github.com/justmoon/node-bignum) diff --git a/blockTemplate.js b/blockTemplate.js index b3042f2..48c5713 100644 --- a/blockTemplate.js +++ b/blockTemplate.js @@ -57,13 +57,16 @@ var BlockTemplate = module.exports = function BlockTemplate(jobId, rpcData, publ var header = new Buffer(80); var position = 0; - header.writeUInt32BE(nonce, position); + header.write(nonce, position, 4, 'hex'); header.write(rpcData.bits, position += 4, 4, 'hex'); - header.writeUInt32BE(nTime, position += 4); + header.write(nTime, position += 4, 4, 'hex'); header.write(merkleRoot, position += 4, 32, 'hex'); header.write(rpcData.previousblockhash, position += 32, 32, 'hex'); header.writeUInt32BE(rpcData.version, position + 32); - var header = reverseBuffer(header); + var header = util.reverseBuffer(header); + + var test = header.toString('hex'); + return header; @@ -86,8 +89,8 @@ var BlockTemplate = module.exports = function BlockTemplate(jobId, rpcData, publ ]); }; - this.registerSubmit = function(extraNonce1Buffer, extraNonce2, nTime, nonce){ - var submission = extraNonce1Buffer.toString('hex') + extraNonce2 + nTime + nonce; + this.registerSubmit = function(extraNonce1, extraNonce2, nTime, nonce){ + var submission = extraNonce1 + extraNonce2 + nTime + nonce; if (submits.indexOf(submission) === -1){ submits.push(submission); return true; diff --git a/jobManager.js b/jobManager.js index 022b464..f33c84d 100644 --- a/jobManager.js +++ b/jobManager.js @@ -34,7 +34,7 @@ var JobCounter = function(){ this.next = function(){ counter++; - if (counter % 0xffff == 0) + if (counter % 0xffff === 0) counter = 1; return counter.toString(16); }; @@ -49,16 +49,31 @@ var JobManager = module.exports = function JobManager(options){ var jobCounter = new JobCounter(); var jobs = {}; + + function CheckNewIfNewBlock(blockTemplate){ var newBlock = true; for(var job in jobs){ - if (jobs[job].rpcData.previousblockhash == blockTemplate.rpcData.previousblockhash) + if (jobs[job].rpcData.previousblockhash === blockTemplate.rpcData.previousblockhash) newBlock = false; } if (newBlock) _this.emit('newBlock', blockTemplate); } + var diffDividend = bignum.fromBuffer(new Buffer((function(){ + switch(options.algorithm){ + case 'sha256': + return '00000000ffff0000000000000000000000000000000000000000000000000000'; + case 'scrypt': + case 'scrypt-jane': + return '0000ffff00000000000000000000000000000000000000000000000000000000'; + case 'quark': + return '000000ffff000000000000000000000000000000000000000000000000000000' + } + })(), 'hex')); + + //public members @@ -72,7 +87,7 @@ var JobManager = module.exports = function JobManager(options){ jobs[this.currentJob.jobId] = this.currentJob; CheckNewIfNewBlock(this.currentJob); }; - this.processShare = function(jobId, difficulty, extraNonce1Buffer, extraNonce2, nTime, nonce){ + this.processShare = function(jobId, difficulty, extraNonce1, extraNonce2, nTime, nonce){ var submitTime = Date.now() / 1000 | 0; @@ -98,20 +113,22 @@ var JobManager = module.exports = function JobManager(options){ return {error: [20, 'incorrect size of nonce']}; - if (!job.registerSubmit(extraNonce1Buffer, extraNonce2, nTime, nonce)) + if (!job.registerSubmit(extraNonce1, extraNonce2, nTime, nonce)) return {error: [22, 'duplicate share', null]}; + var extraNonce1Buffer = new Buffer(extraNonce1, 'hex'); var extraNonce2Buffer = new Buffer(extraNonce2, 'hex'); var coinbaseBuffer = job.serializeCoinbase(extraNonce1Buffer, extraNonce2Buffer); var coinbaseHash = util.doublesha(coinbaseBuffer); - - var merkleRoot = job.merkleTree.withFirst(coinbaseHash).toString('hex'); + var merkleRoot = job.merkleTree.withFirst(coinbaseHash); + for (var i = 0; i < 8; i++) merkleRoot.writeUInt32LE(merkleRoot.readUInt32BE(i * 4), i * 4); + merkleRoot = util.reverseBuffer(merkleRoot).toString('hex'); var headerBuffer = job.serializeHeader(merkleRoot, nTime, nonce); - + for (var i = 0; i < 20; i++) headerBuffer.writeUInt32LE(headerBuffer.readUInt32BE(i * 4), i * 4); var headerHash = (function(){ switch(options.algorithm){ case 'sha256': @@ -125,17 +142,19 @@ var JobManager = module.exports = function JobManager(options){ } })(); - var headerBigNum = bignum.fromBuffer(headerHash); - var targetUser = bignum.fromBuffer( - new Buffer('00000000ffff0000000000000000000000000000000000000000000000000000', 'hex') - ).div(difficulty); - if (headerBigNum.gt(targetUser)) + var headerBigNum = bignum.fromBuffer(headerHash, {endian: 'little', size: 32}); + + if (job.target.ge(headerBigNum)){ + var blockHex = job.serializeBlock(headerBuffer, coinbaseBuffer); + _this.emit('blockFound', blockHex); + } + + var targetUser = diffDividend.div(difficulty); + if (headerBigNum.gt(targetUser)){ + console.log('target:' + targetUser.toString()); + console.log('share:' + headerBigNum.toString()); return {error: [23, 'low difficulty share', null]}; - - - if (headerBigNum.gt(job.target)){ - _this.emit('blockFound', job.serializeBlock(headerBuffer, coinbaseBuffer)); } return {result: true}; diff --git a/main.js b/main.js index 182b84b..d5ee1cf 100644 --- a/main.js +++ b/main.js @@ -18,6 +18,7 @@ var coins = [ reward: 'POW', //or POS address: 'D5uXR7F6bTCJKRZBqj1D4gyHF9MHAd5oNs', stratumPort: 3333, + difficulty: 8, daemon: { bin: 'dogecoind', port: 8332, diff --git a/merkleTree.js b/merkleTree.js index 10cebbc..90f9c29 100644 --- a/merkleTree.js +++ b/merkleTree.js @@ -24,7 +24,7 @@ var MerkleTree = module.exports = function MerkleTree(data){ if (Ll > 1){ while (true){ - if (Ll == 1) + if (Ll === 1) break; steps.push(L[1]); diff --git a/pool.js b/pool.js index 2faae2f..dd0731e 100644 --- a/pool.js +++ b/pool.js @@ -21,13 +21,22 @@ var pool = module.exports = function pool(coin){ }); this.jobManager.on('newBlock', function(blockTemplate){ _this.stratumServer.broadcastMiningJobs(blockTemplate.getJobParams()); - }).on('blockFound', function(blockBuffer){ - _this.daemon.cmd('submitblock', - [blockBuffer.toString('hex')], - function(error, result){ + }).on('blockFound', function(blockHex){ - } - ); + if (coin.options.hasSubmitMethod) + _this.daemon.cmd('submitblock', + [blockHex], + function(error, result){ + + } + ); + else + _this.daemon.cmd('getblocktemplate', + [{'mode': 'submit', 'data': blockHex}], + function(error, result){ + + } + ); }); @@ -68,7 +77,6 @@ var pool = module.exports = function pool(coin){ _this.daemon.cmd('submitblock', [], function(error, result){ - console.log(error); if (error && error.message === 'Method not found') callback(null, false); else @@ -104,19 +112,22 @@ var pool = module.exports = function pool(coin){ client.on('subscription', function(params, resultCallback){ var extraNonce = _this.jobManager.extraNonceCounter.next(); var extraNonce2Size = _this.jobManager.extraNonce2Size; - resultCallback(null, extraNonce, extraNonce2Size); - this.sendDifficulty(1); + resultCallback(null, + extraNonce, + extraNonce2Size + ); + this.sendDifficulty(coin.options.difficulty); this.sendMiningJob(_this.jobManager.currentJob.getJobParams()); }).on('authorize', function(params, resultCallback){ resultCallback(null, true); }).on('submit', function(params, resultCallback){ var result =_this.jobManager.processShare( - result.jobId, + params.jobId, client.difficulty, client.extraNonce1, - result.extraNonce2, - result.nTime, - result.nonce + params.extraNonce2, + params.nTime, + params.nonce ); if (result.error){ resultCallback(result.error); diff --git a/python/litecoin_scrypt-master/build/lib.linux-x86_64-2.7/ltc_scrypt.so b/python/litecoin_scrypt-master/build/lib.linux-x86_64-2.7/ltc_scrypt.so new file mode 100755 index 0000000..ed9ef76 Binary files /dev/null and b/python/litecoin_scrypt-master/build/lib.linux-x86_64-2.7/ltc_scrypt.so differ diff --git a/python/litecoin_scrypt-master/build/temp.linux-x86_64-2.7/scrypt.o b/python/litecoin_scrypt-master/build/temp.linux-x86_64-2.7/scrypt.o new file mode 100644 index 0000000..cc563bb Binary files /dev/null and b/python/litecoin_scrypt-master/build/temp.linux-x86_64-2.7/scrypt.o differ diff --git a/python/litecoin_scrypt-master/build/temp.linux-x86_64-2.7/scryptmodule.o b/python/litecoin_scrypt-master/build/temp.linux-x86_64-2.7/scryptmodule.o new file mode 100644 index 0000000..a9e0f31 Binary files /dev/null and b/python/litecoin_scrypt-master/build/temp.linux-x86_64-2.7/scryptmodule.o differ diff --git a/python/litecoin_scrypt-master/scrypt.c b/python/litecoin_scrypt-master/scrypt.c new file mode 100644 index 0000000..29a6088 --- /dev/null +++ b/python/litecoin_scrypt-master/scrypt.c @@ -0,0 +1,681 @@ +/*- + * Copyright 2009 Colin Percival, 2011 ArtForz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ + +#include "scrypt.h" +#include +#include +#include + +static __inline uint32_t +be32dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + + return ((uint32_t)(p[3]) + ((uint32_t)(p[2]) << 8) + + ((uint32_t)(p[1]) << 16) + ((uint32_t)(p[0]) << 24)); +} + +static __inline void +be32enc(void *pp, uint32_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[3] = x & 0xff; + p[2] = (x >> 8) & 0xff; + p[1] = (x >> 16) & 0xff; + p[0] = (x >> 24) & 0xff; +} + +static __inline uint32_t +le32dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + + return ((uint32_t)(p[0]) + ((uint32_t)(p[1]) << 8) + + ((uint32_t)(p[2]) << 16) + ((uint32_t)(p[3]) << 24)); +} + +static __inline void +le32enc(void *pp, uint32_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[0] = x & 0xff; + p[1] = (x >> 8) & 0xff; + p[2] = (x >> 16) & 0xff; + p[3] = (x >> 24) & 0xff; +} + + +typedef struct SHA256Context { + uint32_t state[8]; + uint32_t count[2]; + unsigned char buf[64]; +} SHA256_CTX; + +typedef struct HMAC_SHA256Context { + SHA256_CTX ictx; + SHA256_CTX octx; +} HMAC_SHA256_CTX; + +/* + * Encode a length len/4 vector of (uint32_t) into a length len vector of + * (unsigned char) in big-endian form. Assumes len is a multiple of 4. + */ +static void +be32enc_vect(unsigned char *dst, const uint32_t *src, size_t len) +{ + size_t i; + + for (i = 0; i < len / 4; i++) + be32enc(dst + i * 4, src[i]); +} + +/* + * Decode a big-endian length len vector of (unsigned char) into a length + * len/4 vector of (uint32_t). Assumes len is a multiple of 4. + */ +static void +be32dec_vect(uint32_t *dst, const unsigned char *src, size_t len) +{ + size_t i; + + for (i = 0; i < len / 4; i++) + dst[i] = be32dec(src + i * 4); +} + +/* Elementary functions used by SHA256 */ +#define Ch(x, y, z) ((x & (y ^ z)) ^ z) +#define Maj(x, y, z) ((x & (y | z)) | (y & z)) +#define SHR(x, n) (x >> n) +#define ROTR(x, n) ((x >> n) | (x << (32 - n))) +#define S0(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22)) +#define S1(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25)) +#define s0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3)) +#define s1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10)) + +/* SHA256 round function */ +#define RND(a, b, c, d, e, f, g, h, k) \ + t0 = h + S1(e) + Ch(e, f, g) + k; \ + t1 = S0(a) + Maj(a, b, c); \ + d += t0; \ + h = t0 + t1; + +/* Adjusted round function for rotating state */ +#define RNDr(S, W, i, k) \ + RND(S[(64 - i) % 8], S[(65 - i) % 8], \ + S[(66 - i) % 8], S[(67 - i) % 8], \ + S[(68 - i) % 8], S[(69 - i) % 8], \ + S[(70 - i) % 8], S[(71 - i) % 8], \ + W[i] + k) + +/* + * SHA256 block compression function. The 256-bit state is transformed via + * the 512-bit input block to produce a new state. + */ +static void +SHA256_Transform(uint32_t * state, const unsigned char block[64]) +{ + uint32_t W[64]; + uint32_t S[8]; + uint32_t t0, t1; + int i; + + /* 1. Prepare message schedule W. */ + be32dec_vect(W, block, 64); + for (i = 16; i < 64; i++) + W[i] = s1(W[i - 2]) + W[i - 7] + s0(W[i - 15]) + W[i - 16]; + + /* 2. Initialize working variables. */ + memcpy(S, state, 32); + + /* 3. Mix. */ + RNDr(S, W, 0, 0x428a2f98); + RNDr(S, W, 1, 0x71374491); + RNDr(S, W, 2, 0xb5c0fbcf); + RNDr(S, W, 3, 0xe9b5dba5); + RNDr(S, W, 4, 0x3956c25b); + RNDr(S, W, 5, 0x59f111f1); + RNDr(S, W, 6, 0x923f82a4); + RNDr(S, W, 7, 0xab1c5ed5); + RNDr(S, W, 8, 0xd807aa98); + RNDr(S, W, 9, 0x12835b01); + RNDr(S, W, 10, 0x243185be); + RNDr(S, W, 11, 0x550c7dc3); + RNDr(S, W, 12, 0x72be5d74); + RNDr(S, W, 13, 0x80deb1fe); + RNDr(S, W, 14, 0x9bdc06a7); + RNDr(S, W, 15, 0xc19bf174); + RNDr(S, W, 16, 0xe49b69c1); + RNDr(S, W, 17, 0xefbe4786); + RNDr(S, W, 18, 0x0fc19dc6); + RNDr(S, W, 19, 0x240ca1cc); + RNDr(S, W, 20, 0x2de92c6f); + RNDr(S, W, 21, 0x4a7484aa); + RNDr(S, W, 22, 0x5cb0a9dc); + RNDr(S, W, 23, 0x76f988da); + RNDr(S, W, 24, 0x983e5152); + RNDr(S, W, 25, 0xa831c66d); + RNDr(S, W, 26, 0xb00327c8); + RNDr(S, W, 27, 0xbf597fc7); + RNDr(S, W, 28, 0xc6e00bf3); + RNDr(S, W, 29, 0xd5a79147); + RNDr(S, W, 30, 0x06ca6351); + RNDr(S, W, 31, 0x14292967); + RNDr(S, W, 32, 0x27b70a85); + RNDr(S, W, 33, 0x2e1b2138); + RNDr(S, W, 34, 0x4d2c6dfc); + RNDr(S, W, 35, 0x53380d13); + RNDr(S, W, 36, 0x650a7354); + RNDr(S, W, 37, 0x766a0abb); + RNDr(S, W, 38, 0x81c2c92e); + RNDr(S, W, 39, 0x92722c85); + RNDr(S, W, 40, 0xa2bfe8a1); + RNDr(S, W, 41, 0xa81a664b); + RNDr(S, W, 42, 0xc24b8b70); + RNDr(S, W, 43, 0xc76c51a3); + RNDr(S, W, 44, 0xd192e819); + RNDr(S, W, 45, 0xd6990624); + RNDr(S, W, 46, 0xf40e3585); + RNDr(S, W, 47, 0x106aa070); + RNDr(S, W, 48, 0x19a4c116); + RNDr(S, W, 49, 0x1e376c08); + RNDr(S, W, 50, 0x2748774c); + RNDr(S, W, 51, 0x34b0bcb5); + RNDr(S, W, 52, 0x391c0cb3); + RNDr(S, W, 53, 0x4ed8aa4a); + RNDr(S, W, 54, 0x5b9cca4f); + RNDr(S, W, 55, 0x682e6ff3); + RNDr(S, W, 56, 0x748f82ee); + RNDr(S, W, 57, 0x78a5636f); + RNDr(S, W, 58, 0x84c87814); + RNDr(S, W, 59, 0x8cc70208); + RNDr(S, W, 60, 0x90befffa); + RNDr(S, W, 61, 0xa4506ceb); + RNDr(S, W, 62, 0xbef9a3f7); + RNDr(S, W, 63, 0xc67178f2); + + /* 4. Mix local working variables into global state */ + for (i = 0; i < 8; i++) + state[i] += S[i]; + + /* Clean the stack. */ + memset(W, 0, 256); + memset(S, 0, 32); + t0 = t1 = 0; +} + +static unsigned char PAD[64] = { + 0x80, 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 +}; + +/* SHA-256 initialization. Begins a SHA-256 operation. */ +static void +SHA256_Init(SHA256_CTX * ctx) +{ + + /* Zero bits processed so far */ + ctx->count[0] = ctx->count[1] = 0; + + /* Magic initialization constants */ + ctx->state[0] = 0x6A09E667; + ctx->state[1] = 0xBB67AE85; + ctx->state[2] = 0x3C6EF372; + ctx->state[3] = 0xA54FF53A; + ctx->state[4] = 0x510E527F; + ctx->state[5] = 0x9B05688C; + ctx->state[6] = 0x1F83D9AB; + ctx->state[7] = 0x5BE0CD19; +} + +/* Add bytes into the hash */ +static void +SHA256_Update(SHA256_CTX * ctx, const void *in, size_t len) +{ + uint32_t bitlen[2]; + uint32_t r; + const unsigned char *src = in; + + /* Number of bytes left in the buffer from previous updates */ + r = (ctx->count[1] >> 3) & 0x3f; + + /* Convert the length into a number of bits */ + bitlen[1] = ((uint32_t)len) << 3; + bitlen[0] = (uint32_t)(len >> 29); + + /* Update number of bits */ + if ((ctx->count[1] += bitlen[1]) < bitlen[1]) + ctx->count[0]++; + ctx->count[0] += bitlen[0]; + + /* Handle the case where we don't need to perform any transforms */ + if (len < 64 - r) { + memcpy(&ctx->buf[r], src, len); + return; + } + + /* Finish the current block */ + memcpy(&ctx->buf[r], src, 64 - r); + SHA256_Transform(ctx->state, ctx->buf); + src += 64 - r; + len -= 64 - r; + + /* Perform complete blocks */ + while (len >= 64) { + SHA256_Transform(ctx->state, src); + src += 64; + len -= 64; + } + + /* Copy left over data into buffer */ + memcpy(ctx->buf, src, len); +} + +/* Add padding and terminating bit-count. */ +static void +SHA256_Pad(SHA256_CTX * ctx) +{ + unsigned char len[8]; + uint32_t r, plen; + + /* + * Convert length to a vector of bytes -- we do this now rather + * than later because the length will change after we pad. + */ + be32enc_vect(len, ctx->count, 8); + + /* Add 1--64 bytes so that the resulting length is 56 mod 64 */ + r = (ctx->count[1] >> 3) & 0x3f; + plen = (r < 56) ? (56 - r) : (120 - r); + SHA256_Update(ctx, PAD, (size_t)plen); + + /* Add the terminating bit-count */ + SHA256_Update(ctx, len, 8); +} + +/* + * SHA-256 finalization. Pads the input data, exports the hash value, + * and clears the context state. + */ +static void +SHA256_Final(unsigned char digest[32], SHA256_CTX * ctx) +{ + + /* Add padding */ + SHA256_Pad(ctx); + + /* Write the hash */ + be32enc_vect(digest, ctx->state, 32); + + /* Clear the context state */ + memset((void *)ctx, 0, sizeof(*ctx)); +} + +/* Initialize an HMAC-SHA256 operation with the given key. */ +static void +HMAC_SHA256_Init(HMAC_SHA256_CTX * ctx, const void * _K, size_t Klen) +{ + unsigned char pad[64]; + unsigned char khash[32]; + const unsigned char * K = _K; + size_t i; + + /* If Klen > 64, the key is really SHA256(K). */ + if (Klen > 64) { + SHA256_Init(&ctx->ictx); + SHA256_Update(&ctx->ictx, K, Klen); + SHA256_Final(khash, &ctx->ictx); + K = khash; + Klen = 32; + } + + /* Inner SHA256 operation is SHA256(K xor [block of 0x36] || data). */ + SHA256_Init(&ctx->ictx); + memset(pad, 0x36, 64); + for (i = 0; i < Klen; i++) + pad[i] ^= K[i]; + SHA256_Update(&ctx->ictx, pad, 64); + + /* Outer SHA256 operation is SHA256(K xor [block of 0x5c] || hash). */ + SHA256_Init(&ctx->octx); + memset(pad, 0x5c, 64); + for (i = 0; i < Klen; i++) + pad[i] ^= K[i]; + SHA256_Update(&ctx->octx, pad, 64); + + /* Clean the stack. */ + memset(khash, 0, 32); +} + +/* Add bytes to the HMAC-SHA256 operation. */ +static void +HMAC_SHA256_Update(HMAC_SHA256_CTX * ctx, const void *in, size_t len) +{ + + /* Feed data to the inner SHA256 operation. */ + SHA256_Update(&ctx->ictx, in, len); +} + +/* Finish an HMAC-SHA256 operation. */ +static void +HMAC_SHA256_Final(unsigned char digest[32], HMAC_SHA256_CTX * ctx) +{ + unsigned char ihash[32]; + + /* Finish the inner SHA256 operation. */ + SHA256_Final(ihash, &ctx->ictx); + + /* Feed the inner hash to the outer SHA256 operation. */ + SHA256_Update(&ctx->octx, ihash, 32); + + /* Finish the outer SHA256 operation. */ + SHA256_Final(digest, &ctx->octx); + + /* Clean the stack. */ + memset(ihash, 0, 32); +} + +/** + * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen): + * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and + * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1). + */ +static void +PBKDF2_SHA256(const uint8_t * passwd, size_t passwdlen, const uint8_t * salt, + size_t saltlen, uint64_t c, uint8_t * buf, size_t dkLen) +{ + HMAC_SHA256_CTX PShctx, hctx; + size_t i; + uint8_t ivec[4]; + uint8_t U[32]; + uint8_t T[32]; + uint64_t j; + int k; + size_t clen; + + /* Compute HMAC state after processing P and S. */ + HMAC_SHA256_Init(&PShctx, passwd, passwdlen); + HMAC_SHA256_Update(&PShctx, salt, saltlen); + + /* Iterate through the blocks. */ + for (i = 0; i * 32 < dkLen; i++) { + /* Generate INT(i + 1). */ + be32enc(ivec, (uint32_t)(i + 1)); + + /* Compute U_1 = PRF(P, S || INT(i)). */ + memcpy(&hctx, &PShctx, sizeof(HMAC_SHA256_CTX)); + HMAC_SHA256_Update(&hctx, ivec, 4); + HMAC_SHA256_Final(U, &hctx); + + /* T_i = U_1 ... */ + memcpy(T, U, 32); + + for (j = 2; j <= c; j++) { + /* Compute U_j. */ + HMAC_SHA256_Init(&hctx, passwd, passwdlen); + HMAC_SHA256_Update(&hctx, U, 32); + HMAC_SHA256_Final(U, &hctx); + + /* ... xor U_j ... */ + for (k = 0; k < 32; k++) + T[k] ^= U[k]; + } + + /* Copy as many bytes as necessary into buf. */ + clen = dkLen - i * 32; + if (clen > 32) + clen = 32; + memcpy(&buf[i * 32], T, clen); + } + + /* Clean PShctx, since we never called _Final on it. */ + memset(&PShctx, 0, sizeof(HMAC_SHA256_CTX)); +} + + +static void blkcpy(void *, void *, size_t); +static void blkxor(void *, void *, size_t); +static void salsa20_8(uint32_t[16]); +static void blockmix_salsa8(uint32_t *, uint32_t *, uint32_t *, size_t); +static uint64_t integerify(void *, size_t); +static void smix(uint8_t *, size_t, uint64_t, uint32_t *, uint32_t *); + +static void +blkcpy(void * dest, void * src, size_t len) +{ + size_t * D = dest; + size_t * S = src; + size_t L = len / sizeof(size_t); + size_t i; + + for (i = 0; i < L; i++) + D[i] = S[i]; +} + +static void +blkxor(void * dest, void * src, size_t len) +{ + size_t * D = dest; + size_t * S = src; + size_t L = len / sizeof(size_t); + size_t i; + + for (i = 0; i < L; i++) + D[i] ^= S[i]; +} + +/** + * salsa20_8(B): + * Apply the salsa20/8 core to the provided block. + */ +static void +salsa20_8(uint32_t B[16]) +{ + uint32_t x[16]; + size_t i; + + blkcpy(x, B, 64); + for (i = 0; i < 8; i += 2) { +#define R(a,b) (((a) << (b)) | ((a) >> (32 - (b)))) + /* Operate on columns. */ + x[ 4] ^= R(x[ 0]+x[12], 7); x[ 8] ^= R(x[ 4]+x[ 0], 9); + x[12] ^= R(x[ 8]+x[ 4],13); x[ 0] ^= R(x[12]+x[ 8],18); + + x[ 9] ^= R(x[ 5]+x[ 1], 7); x[13] ^= R(x[ 9]+x[ 5], 9); + x[ 1] ^= R(x[13]+x[ 9],13); x[ 5] ^= R(x[ 1]+x[13],18); + + x[14] ^= R(x[10]+x[ 6], 7); x[ 2] ^= R(x[14]+x[10], 9); + x[ 6] ^= R(x[ 2]+x[14],13); x[10] ^= R(x[ 6]+x[ 2],18); + + x[ 3] ^= R(x[15]+x[11], 7); x[ 7] ^= R(x[ 3]+x[15], 9); + x[11] ^= R(x[ 7]+x[ 3],13); x[15] ^= R(x[11]+x[ 7],18); + + /* Operate on rows. */ + x[ 1] ^= R(x[ 0]+x[ 3], 7); x[ 2] ^= R(x[ 1]+x[ 0], 9); + x[ 3] ^= R(x[ 2]+x[ 1],13); x[ 0] ^= R(x[ 3]+x[ 2],18); + + x[ 6] ^= R(x[ 5]+x[ 4], 7); x[ 7] ^= R(x[ 6]+x[ 5], 9); + x[ 4] ^= R(x[ 7]+x[ 6],13); x[ 5] ^= R(x[ 4]+x[ 7],18); + + x[11] ^= R(x[10]+x[ 9], 7); x[ 8] ^= R(x[11]+x[10], 9); + x[ 9] ^= R(x[ 8]+x[11],13); x[10] ^= R(x[ 9]+x[ 8],18); + + x[12] ^= R(x[15]+x[14], 7); x[13] ^= R(x[12]+x[15], 9); + x[14] ^= R(x[13]+x[12],13); x[15] ^= R(x[14]+x[13],18); +#undef R + } + for (i = 0; i < 16; i++) + B[i] += x[i]; +} + +/** + * blockmix_salsa8(Bin, Bout, X, r): + * Compute Bout = BlockMix_{salsa20/8, r}(Bin). The input Bin must be 128r + * bytes in length; the output Bout must also be the same size. The + * temporary space X must be 64 bytes. + */ +static void +blockmix_salsa8(uint32_t * Bin, uint32_t * Bout, uint32_t * X, size_t r) +{ + size_t i; + + /* 1: X <-- B_{2r - 1} */ + blkcpy(X, &Bin[(2 * r - 1) * 16], 64); + + /* 2: for i = 0 to 2r - 1 do */ + for (i = 0; i < 2 * r; i += 2) { + /* 3: X <-- H(X \xor B_i) */ + blkxor(X, &Bin[i * 16], 64); + salsa20_8(X); + + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + blkcpy(&Bout[i * 8], X, 64); + + /* 3: X <-- H(X \xor B_i) */ + blkxor(X, &Bin[i * 16 + 16], 64); + salsa20_8(X); + + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + blkcpy(&Bout[i * 8 + r * 16], X, 64); + } +} + +/** + * integerify(B, r): + * Return the result of parsing B_{2r-1} as a little-endian integer. + */ +static uint64_t +integerify(void * B, size_t r) +{ + uint32_t * X = (void *)((uintptr_t)(B) + (2 * r - 1) * 64); + + return (((uint64_t)(X[1]) << 32) + X[0]); +} + +/** + * smix(B, r, N, V, XY): + * Compute B = SMix_r(B, N). The input B must be 128r bytes in length; + * the temporary storage V must be 128rN bytes in length; the temporary + * storage XY must be 256r + 64 bytes in length. The value N must be a + * power of 2 greater than 1. The arrays B, V, and XY must be aligned to a + * multiple of 64 bytes. + */ +static void +smix(uint8_t * B, size_t r, uint64_t N, uint32_t * V, uint32_t * XY) +{ + uint32_t * X = XY; + uint32_t * Y = &XY[32 * r]; + uint32_t * Z = &XY[64 * r]; + uint64_t i; + uint64_t j; + size_t k; + + /* 1: X <-- B */ + for (k = 0; k < 32 * r; k++) + X[k] = le32dec(&B[4 * k]); + + /* 2: for i = 0 to N - 1 do */ + for (i = 0; i < N; i += 2) { + /* 3: V_i <-- X */ + blkcpy(&V[i * (32 * r)], X, 128 * r); + + /* 4: X <-- H(X) */ + blockmix_salsa8(X, Y, Z, r); + + /* 3: V_i <-- X */ + blkcpy(&V[(i + 1) * (32 * r)], Y, 128 * r); + + /* 4: X <-- H(X) */ + blockmix_salsa8(Y, X, Z, r); + } + + /* 6: for i = 0 to N - 1 do */ + for (i = 0; i < N; i += 2) { + /* 7: j <-- Integerify(X) mod N */ + j = integerify(X, r) & (N - 1); + + /* 8: X <-- H(X \xor V_j) */ + blkxor(X, &V[j * (32 * r)], 128 * r); + blockmix_salsa8(X, Y, Z, r); + + /* 7: j <-- Integerify(X) mod N */ + j = integerify(Y, r) & (N - 1); + + /* 8: X <-- H(X \xor V_j) */ + blkxor(Y, &V[j * (32 * r)], 128 * r); + blockmix_salsa8(Y, X, Z, r); + } + + /* 10: B' <-- X */ + for (k = 0; k < 32 * r; k++) + le32enc(&B[4 * k], X[k]); +} + +/* cpu and memory intensive function to transform a 80 byte buffer into a 32 byte output + scratchpad size needs to be at least 63 + (128 * r * p) + (256 * r + 64) + (128 * r * N) bytes + */ +void scrypt_1024_1_1_256_sp(const char* input, char* output, char* scratchpad) +{ + uint8_t * B; + uint32_t * V; + uint32_t * XY; + uint32_t i; + + const uint32_t N = 1024; + const uint32_t r = 1; + const uint32_t p = 1; + + B = (uint8_t *)(((uintptr_t)(scratchpad) + 63) & ~ (uintptr_t)(63)); + XY = (uint32_t *)(B + (128 * r * p)); + V = (uint32_t *)(B + (128 * r * p) + (256 * r + 64)); + + /* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */ + PBKDF2_SHA256((const uint8_t*)input, 80, (const uint8_t*)input, 80, 1, B, p * 128 * r); + + /* 2: for i = 0 to p - 1 do */ + for (i = 0; i < p; i++) { + /* 3: B_i <-- MF(B_i, N) */ + smix(&B[i * 128 * r], r, N, V, XY); + } + + /* 5: DK <-- PBKDF2(P, B, 1, dkLen) */ + PBKDF2_SHA256((const uint8_t*)input, 80, B, p * 128 * r, 1, (uint8_t*)output, 32); +} + +void scrypt_1024_1_1_256(const char* input, char* output) +{ + char scratchpad[131583]; + scrypt_1024_1_1_256_sp(input, output, scratchpad); +} + diff --git a/python/litecoin_scrypt-master/scrypt.h b/python/litecoin_scrypt-master/scrypt.h new file mode 100644 index 0000000..7fe9b5c --- /dev/null +++ b/python/litecoin_scrypt-master/scrypt.h @@ -0,0 +1,16 @@ +#ifndef SCRYPT_H +#define SCRYPT_H + +#ifdef __cplusplus +extern "C" { +#endif + +void scrypt_1024_1_1_256(const char* input, char* output); +void scrypt_1024_1_1_256_sp(const char* input, char* output, char* scratchpad); +#define scrypt_scratchpad_size 131583; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/python/litecoin_scrypt-master/scryptmodule.c b/python/litecoin_scrypt-master/scryptmodule.c new file mode 100644 index 0000000..eb8faab --- /dev/null +++ b/python/litecoin_scrypt-master/scryptmodule.c @@ -0,0 +1,57 @@ +#include + +#include "scrypt.h" + +static PyObject *scrypt_getpowhash(PyObject *self, PyObject *args) +{ + char *output; + PyObject *value; +#if PY_MAJOR_VERSION >= 3 + PyBytesObject *input; +#else + PyStringObject *input; +#endif + if (!PyArg_ParseTuple(args, "S", &input)) + return NULL; + Py_INCREF(input); + output = PyMem_Malloc(32); + +#if PY_MAJOR_VERSION >= 3 + scrypt_1024_1_1_256((char *)PyBytes_AsString((PyObject*) input), output); +#else + scrypt_1024_1_1_256((char *)PyString_AsString((PyObject*) input), output); +#endif + Py_DECREF(input); +#if PY_MAJOR_VERSION >= 3 + value = Py_BuildValue("y#", output, 32); +#else + value = Py_BuildValue("s#", output, 32); +#endif + PyMem_Free(output); + return value; +} + +static PyMethodDef ScryptMethods[] = { + { "getPoWHash", scrypt_getpowhash, METH_VARARGS, "Returns the proof of work hash using scrypt" }, + { NULL, NULL, 0, NULL } +}; + +#if PY_MAJOR_VERSION >= 3 +static struct PyModuleDef ScryptModule = { + PyModuleDef_HEAD_INIT, + "ltc_scrypt", + "...", + -1, + ScryptMethods +}; + +PyMODINIT_FUNC PyInit_ltc_scrypt(void) { + return PyModule_Create(&ScryptModule); +} + +#else + +PyMODINIT_FUNC initltc_scrypt(void) { + (void) Py_InitModule("ltc_scrypt", ScryptMethods); +} +#endif diff --git a/python/litecoin_scrypt-master/setup.py b/python/litecoin_scrypt-master/setup.py new file mode 100644 index 0000000..8304844 --- /dev/null +++ b/python/litecoin_scrypt-master/setup.py @@ -0,0 +1,11 @@ +from distutils.core import setup, Extension + +ltc_scrypt_module = Extension('ltc_scrypt', + sources = ['scryptmodule.c', + 'scrypt.c'], + include_dirs=['.']) + +setup (name = 'ltc_scrypt', + version = '1.0', + description = 'Bindings for scrypt proof of work used by Litecoin', + ext_modules = [ltc_scrypt_module]) diff --git a/python/util.py b/python/util.py new file mode 100644 index 0000000..dc164b1 --- /dev/null +++ b/python/util.py @@ -0,0 +1,177 @@ +import binascii +import struct +from hashlib import sha256 +import ltc_scrypt + +def ser_number(n): + # For encoding nHeight into coinbase + s = bytearray(b'\1') + while n > 127: + s[0] += 1 + s.append(n % 256) + n //= 256 + s.append(n) + return bytes(s) + + + +def ser_string(s): + if len(s) < 253: + return chr(len(s)) + s + elif len(s) < 0x10000: + print "here" + return chr(253) + struct.pack("= 256: + div, mod = divmod(long_value, 256) + result = chr(mod) + result + long_value = div + result = chr(long_value) + result + + nPad = 0 + for c in v: + if c == __b58chars[0]: nPad += 1 + else: break + + result = chr(0)*nPad + result + if length is not None and len(result) != length: + return None + + return result + +def address_to_pubkeyhash(addr): + #try: + addr = b58decode(addr, 25) + #except: + # return None + + if addr is None: + return None + + ver = addr[0] + cksumA = addr[-4:] + cksumB = doublesha(addr[:-4])[:4] + + if cksumA != cksumB: + return None + + return (ver, addr[1:-4]) + +def script_to_address(addr): + d = address_to_pubkeyhash(addr) + if not d: + raise ValueError('invalid address') + (ver, pubkeyhash) = d + print "a - " + binascii.hexlify(pubkeyhash) + return b'\x76\xa9\x14' + pubkeyhash + b'\x88\xac' + + +def ser_uint256(u): + rs = "" + for i in xrange(8): + rs += struct.pack(">= 32 + return rs + +def uint256_from_str(s): + r = 0L + t = struct.unpack("I", u & 0xFFFFFFFFL) + u >>= 32 + return rs + +def reverse_hash(h): + # This only revert byte order, nothing more + if len(h) != 64: + raise Exception('hash must have 64 hexa chars') + + return ''.join([ h[56-i:64-i] for i in range(0, 64, 8) ]) + +def serialize_header(merkle_root_int, ntime_bin, nonce_bin, nVersion, nBits, prevhash_bin): + '''Serialize header for calculating block hash''' + r = struct.pack(">i", nVersion) + r += prevhash_bin + r += ser_uint256_be(merkle_root_int) + r += ntime_bin + r += struct.pack(">I", nBits) + r += nonce_bin + return r + + +def diff_to_target(difficulty): + diff1 = 0x0000ffff00000000000000000000000000000000000000000000000000000000 + return diff1 / difficulty + + + +nonce = "cf280000" +nonce_bin = binascii.unhexlify(nonce) + +bits = "1c013403" +nBits = int(bits, 16) + +ntime = "52ce31b9" +ntime_bin = binascii.unhexlify(ntime) + +merkleroot = "38f3e68be0b74813af175b8da506dfa3c3017ff06fed7ae85e3efee655c9f7fd" + +merkle_root_bin = binascii.unhexlify(merkleroot) +merkle_root_int = uint256_from_str(merkle_root_bin) + + +pbh = "fefbf5b855440b6ac8f742e03558a910969a8232cc0436c59c306e1d493ca917" +prevhash_bin = binascii.unhexlify(reverse_hash(pbh)) + +version = 1 + + + +header_bin = serialize_header(merkle_root_int, ntime_bin, nonce_bin, version, nBits, prevhash_bin) +hash_bin = ''.join([ header_bin[i*4:i*4+4][::-1] for i in range(0, 20) ]) +hash_bin = ltc_scrypt.getPoWHash(hash_bin) +hash_int = uint256_from_str(hash_bin) + +target_user = diff_to_target(16) + +print hash_int +print target_user + +if hash_int > target_user: + print 'bad' +else: + print 'good' + + + +for x in range(0, 10): + source = binascii.unhexlify("38f3e68be0b74813af175b8da506dfa3c3017ff06fed7ae85e3efee655c9f7fd"); + print binascii.hexlify(source) + print "hash " + str(x) + " " + binascii.hexlify(ltc_scrypt.getPoWHash(source)) \ No newline at end of file diff --git a/payoutManager.js b/shareManager.js similarity index 100% rename from payoutManager.js rename to shareManager.js diff --git a/stratum.js b/stratum.js index b5340a0..4e0b5ba 100644 --- a/stratum.js +++ b/stratum.js @@ -12,7 +12,7 @@ var SubscriptionCounter = function(){ return { next: function(){ count++; - if (Number.MAX_VALUE == count) count = 0; + if (Number.MAX_VALUE === count) count = 0; return padding + binpack.packUInt64(count, 'big').toString('hex'); } }; @@ -142,6 +142,7 @@ var StratumClient = function(options){ if (dataBuffer.slice(-1) === '\n'){ var messages = dataBuffer.split('\n'); messages.forEach(function(message){ + if (message.trim() === '') return; var messageJson; try{ messageJson = JSON.parse(message); diff --git a/test.js b/test.js index e7eebb6..bdacab6 100644 --- a/test.js +++ b/test.js @@ -1,3 +1,7 @@ +var bignum = require('bignum'); +var scrypt = require('scrypt256-hash'); + + var reverseBuffer = function(buff){ var reversed = new Buffer(buff.length); for (var i = buff.length - 1; i >= 0; i--) @@ -5,6 +9,31 @@ var reverseBuffer = function(buff){ return reversed; }; +var hash = new Buffer("38f3e68be0b74813af175b8da506dfa3c3017ff06fed7ae85e3efee655c9f7fd", 'hex'); +var goal = "8be6f3381348b7e08d5b17afa3df06a5f07f01c3e87aed6fe6fe3e5efdf7c955"; + +var s = scrypt.digest(hash); +console.log(s.toString('hex')); +for (var i = 0; i < 20; i++) s.writeUInt32LE(s.readUInt32BE(i * 4), i * 4); + + +var nHash = new Buffer(hash.length); +for (var i = 0; i < 8; i++) nHash.writeUInt32LE(hash.readUInt32BE(i * 4), i * 4); +console.log('maybe: ' + nHash.toString('hex')); + + +var wow = bignum.fromBuffer(hash, {endian: 'little', size: 32}).toBuffer({endian: 'big', size: 32}).toString('hex'); +console.log(wow); +console.log(wow == goal ? 'good' : 'fuck'); + + +/* +var bb = new Buffer('0100000017a93c491d6e309cc53604cc32829a9610a95835e042f7c86a0b4455b8f5fbfe38f3e68be0b74813af175b8da506dfa3c3017ff06fed7ae85e3efee655c9f7fdb931ce520334011c000028cf', 'hex'); +var hash = scrypt.digest(bb); +console.log(bignum.fromBuffer(hash, {endian: 'little', size: 32}).toString()); +*? + +/* var block = { hash: "409fd235e2fdc7182db92e13eed1b352081d9013ddc90e0acd817e378b8c1d1a", confirmations: 1, @@ -46,4 +75,32 @@ var header = reverseBuffer(header); if (phpResult === header.toString('hex')) console.log('works!!!!!'); else - console.log('fuck'); \ No newline at end of file + console.log('fuck'); + */ + +nonce = "cf280000"; +bits = "1c013403"; +time = "52ce31b9"; +merkleroot = "38f3e68be0b74813af175b8da506dfa3c3017ff06fed7ae85e3efee655c9f7fd"; +pbh = "fefbf5b855440b6ac8f742e03558a910969a8232cc0436c59c306e1d493ca917"; +version = 1; + +merkleroot = reverseBuffer(new Buffer(merkleroot, 'hex')).toString('hex'); + +var serializeHeader = function(){ + + var header = new Buffer(80); + var position = 0; + header.write(nonce, position, 4, 'hex'); + header.write(bits, position += 4, 4, 'hex'); + header.write(time, position += 4, 4, 'hex'); + header.write(merkleroot, position += 4, 32, 'hex'); + header.write(pbh, position += 32, 32, 'hex'); + header.writeUInt32BE(version, position + 32); + var header = reverseBuffer(header); + + var test = header.toString('hex'); + + return header; + +}; diff --git a/util.js b/util.js index ff1358a..2463167 100644 --- a/util.js +++ b/util.js @@ -139,11 +139,11 @@ exports.varIntBuffer = function(n){ }; exports.range = function(start, stop, step){ - if (typeof stop == 'undefined'){ + if (typeof stop === 'undefined'){ stop = start; start = 0; } - if (typeof step == 'undefined'){ + if (typeof step === 'undefined'){ step = 1; } if ((step > 0 && start >= stop) || (step < 0 && start <= stop)){