Skip to content
This repository has been archived by the owner on Sep 16, 2021. It is now read-only.

support litecoin bech32 address #24

Open
wants to merge 3 commits into
base: segwit
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
232 changes: 184 additions & 48 deletions lib/address.js

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions lib/block/block.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ Block.fromBuffer = function fromBuffer(buf) {
* @returns {Block} - A hex encoded string of the block
*/
Block.fromString = function fromString(str) {
var buf = new Buffer(str, 'hex');
var buf = Buffer.from(str, 'hex');
return Block.fromBuffer(buf);
};

Expand All @@ -127,7 +127,7 @@ Block.fromString = function fromString(str) {
*/
Block.fromRawBlock = function fromRawBlock(data) {
if (!BufferUtil.isBuffer(data)) {
data = new Buffer(data, 'binary');
data = Buffer.from(data, 'binary');
}
var br = BufferReader(data);
br.pos = Block.Values.START_OF_BLOCK;
Expand Down Expand Up @@ -275,7 +275,7 @@ Block.prototype.inspect = function inspect() {

Block.Values = {
START_OF_BLOCK: 8, // Start of block in raw block data
NULL_HASH: new Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex')
NULL_HASH: Buffer.from('0000000000000000000000000000000000000000000000000000000000000000', 'hex')
};

module.exports = Block;
11 changes: 5 additions & 6 deletions lib/block/blockheader.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,10 @@ BlockHeader._fromObject = function _fromObject(data) {
var prevHash = data.prevHash;
var merkleRoot = data.merkleRoot;
if (_.isString(data.prevHash)) {
prevHash = BufferUtil.reverse(new Buffer(data.prevHash, 'hex'));
prevHash = BufferUtil.reverse(Buffer.from(data.prevHash, 'hex'));
}
if (_.isString(data.merkleRoot)) {
merkleRoot = BufferUtil.reverse(new Buffer(data.merkleRoot, 'hex'));
merkleRoot = BufferUtil.reverse(Buffer.from(data.merkleRoot, 'hex'));
}
var info = {
hash: data.hash,
Expand Down Expand Up @@ -103,7 +103,7 @@ BlockHeader.fromObject = function fromObject(obj) {
*/
BlockHeader.fromRawBlock = function fromRawBlock(data) {
if (!BufferUtil.isBuffer(data)) {
data = new Buffer(data, 'binary');
data = Buffer.from(data, 'binary');
}
var br = BufferReader(data);
br.pos = BlockHeader.Constants.START_OF_HEADER;
Expand All @@ -125,7 +125,7 @@ BlockHeader.fromBuffer = function fromBuffer(buf) {
* @returns {BlockHeader} - An instance of block header
*/
BlockHeader.fromString = function fromString(str) {
var buf = new Buffer(str, 'hex');
var buf = Buffer.from(str, 'hex');
return BlockHeader.fromBuffer(buf);
};

Expand Down Expand Up @@ -271,8 +271,7 @@ BlockHeader.prototype.validTimestamp = function validTimestamp() {
* @returns {Boolean} - If the proof-of-work hash satisfies the target difficulty
*/
BlockHeader.prototype.validProofOfWork = function validProofOfWork() {
// For Litecoin, we use the scrypt hash to calculate proof of work
var pow = new BN(Hash.scrypt(this.toBuffer()));
var pow = new BN(this.id, 'hex');
var target = this.getTargetDifficulty();

if (pow.cmp(target) > 0) {
Expand Down
53 changes: 47 additions & 6 deletions lib/block/merkleblock.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ var BufferWriter = require('../encoding/bufferwriter');
var Hash = require('../crypto/hash');
var JSUtil = require('../util/js');
var Transaction = require('../transaction');
var errors = require('../errors');
var $ = require('../util/preconditions');

/**
Expand Down Expand Up @@ -63,6 +64,7 @@ function MerkleBlock(arg) {
_.extend(this,info);
this._flagBitsUsed = 0;
this._hashesUsed = 0;

return this;
}

Expand Down Expand Up @@ -101,7 +103,7 @@ MerkleBlock.prototype.toBufferWriter = function toBufferWriter(bw) {
bw.writeUInt32LE(this.numTransactions);
bw.writeVarintNum(this.hashes.length);
for (var i = 0; i < this.hashes.length; i++) {
bw.write(new Buffer(this.hashes[i], 'hex'));
bw.write(Buffer.from(this.hashes[i], 'hex'));
}
bw.writeVarintNum(this.flags.length);
for (i = 0; i < this.flags.length; i++) {
Expand Down Expand Up @@ -149,26 +151,61 @@ MerkleBlock.prototype.validMerkleTree = function validMerkleTree() {
return BufferUtil.equals(root, this.header.merkleRoot);
};

/**
* Return a list of all the txs hash that match the filter
* @returns {Array} - txs hash that match the filter
*/
MerkleBlock.prototype.filterdTxsHash = function filterdTxsHash() {
$.checkState(_.isArray(this.flags), 'MerkleBlock flags is not an array');
$.checkState(_.isArray(this.hashes), 'MerkleBlock hashes is not an array');

// Can't have more hashes than numTransactions
if(this.hashes.length > this.numTransactions) {
throw new errors.MerkleBlock.InvalidMerkleTree();
}

// Can't have more flag bits than num hashes
if(this.flags.length * 8 < this.hashes.length) {
throw new errors.MerkleBlock.InvalidMerkleTree();
}

// If there is only one hash the filter do not match any txs in the block
if(this.hashes.length === 1) {
return [];
};

var height = this._calcTreeHeight();
var opts = { hashesUsed: 0, flagBitsUsed: 0 };
var txs = this._traverseMerkleTree(height, 0, opts, true);
if(opts.hashesUsed !== this.hashes.length) {
throw new errors.MerkleBlock.InvalidMerkleTree();
}
return txs;
};

/**
* Traverse a the tree in this MerkleBlock, validating it along the way
* Modeled after Bitcoin Core merkleblock.cpp TraverseAndExtract()
* @param {Number} - depth - Current height
* @param {Number} - pos - Current position in the tree
* @param {Object} - opts - Object with values that need to be mutated throughout the traversal
* @param {Boolean} - checkForTxs - if true return opts.txs else return the Merkle Hash
* @param {Number} - opts.flagBitsUsed - Number of flag bits used, should start at 0
* @param {Number} - opts.hashesUsed - Number of hashes used, should start at 0
* @param {Array} - opts.txs - Will finish populated by transactions found during traversal
* @param {Array} - opts.txs - Will finish populated by transactions found during traversal that match the filter
* @returns {Buffer|null} - Buffer containing the Merkle Hash for that height
* @returns {Array} - transactions found during traversal that match the filter
* @private
*/
MerkleBlock.prototype._traverseMerkleTree = function traverseMerkleTree(depth, pos, opts) {
MerkleBlock.prototype._traverseMerkleTree = function traverseMerkleTree(depth, pos, opts, checkForTxs) {
/* jshint maxcomplexity: 12*/
/* jshint maxstatements: 20 */

opts = opts || {};
opts.txs = opts.txs || [];
opts.flagBitsUsed = opts.flagBitsUsed || 0;
opts.hashesUsed = opts.hashesUsed || 0;
var checkForTxs = checkForTxs || false;

if(opts.flagBitsUsed > this.flags.length * 8) {
return null;
Expand All @@ -182,14 +219,18 @@ MerkleBlock.prototype._traverseMerkleTree = function traverseMerkleTree(depth, p
if(depth === 0 && isParentOfMatch) {
opts.txs.push(hash);
}
return new Buffer(hash, 'hex');
return Buffer.from(hash, 'hex');
} else {
var left = this._traverseMerkleTree(depth-1, pos*2, opts);
var right = left;
if(pos*2+1 < this._calcTreeWidth(depth-1)) {
right = this._traverseMerkleTree(depth-1, pos*2+1, opts);
}
return Hash.sha256sha256(new Buffer.concat([left, right]));
if (checkForTxs){
return opts.txs;
} else {
return Hash.sha256sha256(new Buffer.concat([left, right]));
};
}
};

Expand Down Expand Up @@ -229,7 +270,7 @@ MerkleBlock.prototype.hasTransaction = function hasTransaction(tx) {
var hash = tx;
if(tx instanceof Transaction) {
// We need to reverse the id hash for the lookup
hash = BufferUtil.reverse(new Buffer(tx.id, 'hex')).toString('hex');
hash = BufferUtil.reverse(Buffer.from(tx.id, 'hex')).toString('hex');
}

var txs = [];
Expand Down
28 changes: 8 additions & 20 deletions lib/crypto/bn.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ var $ = require('../util/preconditions');
var _ = require('lodash');

var reversebuf = function(buf) {
var buf2 = new Buffer(buf.length);
var buf2 = Buffer.alloc(buf.length);
for (var i = 0; i < buf.length; i++) {
buf2[i] = buf[buf.length - 1 - i];
}
Expand Down Expand Up @@ -42,7 +42,7 @@ BN.fromBuffer = function(buf, opts) {
BN.fromSM = function(buf, opts) {
var ret;
if (buf.length === 0) {
return BN.fromBuffer(new Buffer([0]));
return BN.fromBuffer(Buffer.from([0]));
}

var endian = 'big';
Expand Down Expand Up @@ -73,7 +73,7 @@ BN.prototype.toBuffer = function(opts) {
if (opts && opts.size) {
hex = this.toString(16, 2);
var natlen = hex.length / 2;
buf = new Buffer(hex, 'hex');
buf = Buffer.from(hex, 'hex');

if (natlen === opts.size) {
buf = buf;
Expand All @@ -84,7 +84,7 @@ BN.prototype.toBuffer = function(opts) {
}
} else {
hex = this.toString(16, 2);
buf = new Buffer(hex, 'hex');
buf = Buffer.from(hex, 'hex');
}

if (typeof opts !== 'undefined' && opts.endian === 'little') {
Expand All @@ -99,19 +99,19 @@ BN.prototype.toSMBigEndian = function() {
if (this.cmp(BN.Zero) === -1) {
buf = this.neg().toBuffer();
if (buf[0] & 0x80) {
buf = Buffer.concat([new Buffer([0x80]), buf]);
buf = Buffer.concat([Buffer.from([0x80]), buf]);
} else {
buf[0] = buf[0] | 0x80;
}
} else {
buf = this.toBuffer();
if (buf[0] & 0x80) {
buf = Buffer.concat([new Buffer([0x00]), buf]);
buf = Buffer.concat([Buffer.from([0x00]), buf]);
}
}

if (buf.length === 1 & buf[0] === 0) {
buf = new Buffer([]);
buf = Buffer.from([]);
}
return buf;
};
Expand Down Expand Up @@ -172,24 +172,12 @@ BN.prototype.toScriptNumBuffer = function() {
});
};

BN.prototype.gt = function(b) {
return this.cmp(b) > 0;
};

BN.prototype.gte = function(b) {
return this.cmp(b) >= 0;
};

BN.prototype.lt = function(b) {
return this.cmp(b) < 0;
};

BN.trim = function(buf, natlen) {
return buf.slice(natlen - buf.length, buf.length);
};

BN.pad = function(buf, natlen, size) {
var rbuf = new Buffer(size);
var rbuf = Buffer.alloc(size);
for (var i = 0; i < buf.length; i++) {
rbuf[rbuf.length - 1 - i] = buf[buf.length - 1 - i];
}
Expand Down
24 changes: 12 additions & 12 deletions lib/crypto/ecdsa.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,25 +81,25 @@ ECDSA.prototype.deterministicK = function(badrs) {
if (_.isUndefined(badrs)) {
badrs = 0;
}
var v = new Buffer(32);
var v = Buffer.alloc(32);
v.fill(0x01);
var k = new Buffer(32);
var k = Buffer.alloc(32);
k.fill(0x00);
var x = this.privkey.bn.toBuffer({
size: 32
});
var hashbuf = this.endian === 'little' ? BufferUtil.reverse(this.hashbuf) : this.hashbuf
k = Hash.sha256hmac(Buffer.concat([v, new Buffer([0x00]), x, hashbuf]), k);
k = Hash.sha256hmac(Buffer.concat([v, Buffer.from([0x00]), x, hashbuf]), k);
v = Hash.sha256hmac(v, k);
k = Hash.sha256hmac(Buffer.concat([v, new Buffer([0x01]), x, hashbuf]), k);
k = Hash.sha256hmac(Buffer.concat([v, Buffer.from([0x01]), x, hashbuf]), k);
v = Hash.sha256hmac(v, k);
v = Hash.sha256hmac(v, k);
var T = BN.fromBuffer(v);
var N = Point.getN();

// also explained in 3.2, we must ensure T is in the proper range (0, N)
for (var i = 0; i < badrs || !(T.lt(N) && T.gt(BN.Zero)); i++) {
k = Hash.sha256hmac(Buffer.concat([v, new Buffer([0x00])]), k);
k = Hash.sha256hmac(Buffer.concat([v, Buffer.from([0x00])]), k);
v = Hash.sha256hmac(v, k);
v = Hash.sha256hmac(v, k);
T = BN.fromBuffer(v);
Expand Down Expand Up @@ -143,7 +143,7 @@ ECDSA.prototype.toPublicKey = function() {
}

// Compute -e from e
var eNeg = e.neg().mod(n);
var eNeg = e.neg().umod(n);

// 1.6.1 Compute Q = r^-1 (sR - eG)
// Q = r^-1 (sR + -eG)
Expand Down Expand Up @@ -174,15 +174,15 @@ ECDSA.prototype.sigError = function() {
} : undefined);
var n = Point.getN();
var sinv = s.invm(n);
var u1 = sinv.mul(e).mod(n);
var u2 = sinv.mul(r).mod(n);
var u1 = sinv.mul(e).umod(n);
var u2 = sinv.mul(r).umod(n);

var p = Point.getG().mulAdd(u1, this.pubkey.point, u2);
if (p.isInfinity()) {
return 'p is infinity';
}

if (p.getX().mod(n).cmp(r) !== 0) {
if (p.getX().umod(n).cmp(r) !== 0) {
return 'Invalid signature';
} else {
return false;
Expand All @@ -192,7 +192,7 @@ ECDSA.prototype.sigError = function() {
ECDSA.toLowS = function(s) {
//enforce low s
//see BIP 62, "low S values in signatures"
if (s.gt(BN.fromBuffer(new Buffer('7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0', 'hex')))) {
if (s.gt(BN.fromBuffer(Buffer.from('7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0', 'hex')))) {
s = Point.getN().sub(s);
}
return s;
Expand All @@ -211,8 +211,8 @@ ECDSA.prototype._findSignature = function(d, e) {
badrs++;
k = this.k;
Q = G.mul(k);
r = Q.x.mod(N);
s = k.invm(N).mul(e.add(d.mul(r))).mod(N);
r = Q.x.umod(N);
s = k.invm(N).mul(e.add(d.mul(r))).umod(N);
} while (r.cmp(BN.Zero) <= 0 || s.cmp(BN.Zero) <= 0);

s = ECDSA.toLowS(s);
Expand Down
17 changes: 5 additions & 12 deletions lib/crypto/hash.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

var crypto = require('crypto');
var BufferUtil = require('../util/buffer');
var Scrypt = require('scryptsy')
var $ = require('../util/preconditions');

var Hash = module.exports;
Expand Down Expand Up @@ -55,20 +54,20 @@ Hash.hmac = function(hashf, data, key) {
if (key.length > blocksize) {
key = hashf(key);
} else if (key < blocksize) {
var fill = new Buffer(blocksize);
var fill = Buffer.alloc(blocksize);
fill.fill(0);
key.copy(fill);
key = fill;
}

var o_key = new Buffer(blocksize);
var o_key = Buffer.alloc(blocksize);
o_key.fill(0x5c);

var i_key = new Buffer(blocksize);
var i_key = Buffer.alloc(blocksize);
i_key.fill(0x36);

var o_key_pad = new Buffer(blocksize);
var i_key_pad = new Buffer(blocksize);
var o_key_pad = Buffer.alloc(blocksize);
var i_key_pad = Buffer.alloc(blocksize);
for (var i = 0; i < blocksize; i++) {
o_key_pad[i] = o_key[i] ^ key[i];
i_key_pad[i] = i_key[i] ^ key[i];
Expand All @@ -84,9 +83,3 @@ Hash.sha256hmac = function(data, key) {
Hash.sha512hmac = function(data, key) {
return Hash.hmac(Hash.sha512, data, key);
};

// Litecoin Scrypt hashing
Hash.scrypt = function(buf) {
$.checkArgument(BufferUtil.isBuffer(buf));
return BufferUtil.reverse(Scrypt(buf, buf, 1024, 1, 1, 32));
};
Loading