digest: avoid extra allocations.

This commit is contained in:
Christopher Jeffrey 2017-07-12 22:57:50 -07:00
parent 2f51fd1c50
commit 37da047a34
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
15 changed files with 87 additions and 98 deletions

View File

@ -11,7 +11,6 @@
*/
const crypto = require('crypto');
const util = require('../utils/util');
const native = require('../native').binding;
/**
@ -24,7 +23,7 @@ const native = require('../native').binding;
exports.encipher = function encipher(data, key, iv) {
let cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
return util.concat(cipher.update(data), cipher.final());
return Buffer.concat([cipher.update(data), cipher.final()]);
};
/**
@ -38,7 +37,7 @@ exports.encipher = function encipher(data, key, iv) {
exports.decipher = function _decipher(data, key, iv) {
let decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
try {
return util.concat(decipher.update(data), decipher.final());
return Buffer.concat([decipher.update(data), decipher.final()]);
} catch (e) {
throw new Error('Bad key for decryption.');
}

View File

@ -14,6 +14,7 @@
const assert = require('assert');
const hashjs = require('hash.js');
const sha256 = require('./sha256');
const POOL64 = Buffer.allocUnsafe(64);
/**
* Hash with chosen algorithm.
@ -85,6 +86,25 @@ exports.hash256 = function hash256(data) {
return sha256.hash256(data);
};
/**
* Hash left and right hashes with hash256.
* @param {Buffer} left
* @param {Buffer} right
* @returns {Buffer}
*/
exports.root256 = function root256(left, right) {
let data = POOL64;
assert(left.length === 32);
assert(right.length === 32);
left.copy(data, 0);
right.copy(data, 32);
return exports.hash256(data);
};
/**
* Create an HMAC.
* @param {String} alg

View File

@ -10,8 +10,10 @@
* @module crypto.digest
*/
const assert = require('assert');
const crypto = require('crypto');
const native = require('../native').binding;
const POOL64 = Buffer.allocUnsafe(64);
/**
* Hash with chosen algorithm.
@ -74,6 +76,25 @@ exports.hash256 = function hash256(data) {
return exports.sha256(exports.sha256(data));
};
/**
* Hash left and right hashes with hash256.
* @param {Buffer} left
* @param {Buffer} right
* @returns {Buffer}
*/
exports.root256 = function root256(left, right) {
let data = POOL64;
assert(left.length === 32);
assert(right.length === 32);
left.copy(data, 0);
right.copy(data, 32);
return exports.hash256(data);
};
/**
* Create an HMAC.
* @param {String} alg
@ -95,4 +116,5 @@ if (native) {
exports.sha256 = native.sha256;
exports.hash160 = native.hash160;
exports.hash256 = native.hash256;
exports.root256 = native.root256;
}

View File

@ -25,7 +25,6 @@ exports.createTree = function createTree(leaves) {
let nodes = leaves;
let size = leaves.length;
let malleated = false;
let data;
if (size === 0) {
let hash = Buffer.allocUnsafe(32);
@ -34,8 +33,6 @@ exports.createTree = function createTree(leaves) {
return [nodes, malleated];
}
data = Buffer.allocUnsafe(64);
for (let j = 0; size > 1; size = (size + 1) >>> 1) {
for (let i = 0; i < size; i += 2) {
let k = Math.min(i + 1, size - 1);
@ -48,10 +45,7 @@ exports.createTree = function createTree(leaves) {
malleated = true;
}
left.copy(data, 0);
right.copy(data, 32);
hash = digest.hash256(data);
hash = digest.root256(left, right);
nodes.push(hash);
}
@ -108,25 +102,17 @@ exports.createBranch = function createBranch(index, leaves) {
*/
exports.verifyBranch = function verifyBranch(hash, branch, index) {
let data;
if (branch.length === 0)
return hash;
data = Buffer.allocUnsafe(64);
for (let i = 0; i < branch.length; i++) {
let otherside = branch[i];
if (index & 1) {
otherside.copy(data, 0);
hash.copy(data, 32);
} else {
hash.copy(data, 0);
otherside.copy(data, 32);
}
if (index & 1)
hash = digest.root256(otherside, hash);
else
hash = digest.root256(hash, otherside);
hash = digest.hash256(data);
index >>>= 1;
}

View File

@ -276,18 +276,18 @@ Miner.prototype.assemble = function assemble(attempt) {
if (tx.isCoinbase())
throw new Error('Cannot add coinbase to block.');
for (let input of tx.inputs) {
let prev = input.prevout.hash;
for (let {prevout} of tx.inputs) {
let hash = prevout.hash;
if (!this.mempool.hasEntry(prev))
if (!this.mempool.hasEntry(hash))
continue;
item.depCount += 1;
if (!depMap[prev])
depMap[prev] = [];
if (!depMap[hash])
depMap[hash] = [];
depMap[prev].push(item);
depMap[hash].push(item);
}
if (item.depCount > 0)
@ -344,7 +344,7 @@ Miner.prototype.assemble = function assemble(attempt) {
if (!deps)
continue;
for (item of deps) {
for (let item of deps) {
if (--item.depCount === 0)
queue.insert(item);
}

View File

@ -173,7 +173,7 @@ BlockTemplate.fromOptions = function fromOptions(options) {
BlockTemplate.prototype.getWitnessHash = function getWitnessHash() {
let nonce = encoding.ZERO_HASH;
let leaves = [];
let root, malleated, data;
let root, malleated;
leaves.push(encoding.ZERO_HASH);
@ -184,9 +184,7 @@ BlockTemplate.prototype.getWitnessHash = function getWitnessHash() {
assert(!malleated);
data = util.concat(root, nonce);
return digest.hash256(data);
return digest.root256(root, nonce);
};
/**
@ -697,10 +695,8 @@ function MerkleTree() {
}
MerkleTree.prototype.withFirst = function withFirst(hash) {
for (let step of this.steps) {
let data = util.concat(hash, step);
hash = digest.hash256(data);
}
for (let step of this.steps)
hash = digest.root256(hash, step);
return hash;
};
@ -757,8 +753,7 @@ MerkleTree.prototype.fromLeaves = function fromLeaves(leaves) {
leaves.push(leaves[len - 1]);
for (let i = 2; i < len; i += 2) {
let data = util.concat(leaves[i], leaves[i + 1]);
let hash = digest.hash256(data);
let hash = digest.root256(leaves[i], leaves[i + 1]);
hashes.push(hash);
}

View File

@ -400,7 +400,7 @@ CompactBlock.prototype.hasIndex = function hasIndex(index) {
*/
CompactBlock.prototype.initKey = function initKey() {
let data = util.concat(this.abbr(), this.keyNonce);
let data = Buffer.concat([this.abbr(), this.keyNonce]);
let hash = digest.sha256(data);
this.sipKey = hash.slice(0, 16);
};

View File

@ -20,6 +20,7 @@ const seeds = require('./seeds');
const dns = require('./dns');
const Logger = require('../node/logger');
const fs = require('../utils/fs');
const POOL32 = Buffer.allocUnsafe(32);
/**
* Host List
@ -459,7 +460,7 @@ HostList.prototype.getHost = function getHost() {
HostList.prototype.freshBucket = function freshBucket(entry) {
let addr = entry.addr;
let src = entry.src;
let data = util.concat(addr.raw, src.raw);
let data = concat32(addr.raw, src.raw);
let hash = murmur3(data, 0xfba4c795);
let index = hash % this.fresh.length;
return this.fresh[index];
@ -1588,6 +1589,17 @@ HostListOptions.prototype.fromOptions = function fromOptions(options) {
return this;
};
/*
* Helpers
*/
function concat32(left, right) {
let data = POOL32;
left.copy(data, 0);
right.copy(data, 32);
return data;
}
/*
* Expose
*/

View File

@ -298,7 +298,7 @@ Block.prototype.createMerkleRoot = function createMerkleRoot(enc) {
*/
Block.prototype.createWitnessNonce = function createWitnessNonce() {
return util.copy(encoding.ZERO_HASH);
return Buffer.from(encoding.ZERO_HASH);
};
/**
@ -311,7 +311,7 @@ Block.prototype.createWitnessNonce = function createWitnessNonce() {
Block.prototype.createCommitmentHash = function createCommitmentHash(enc) {
let nonce = this.getWitnessNonce();
let leaves = [];
let root, data, hash;
let root, hash;
assert(nonce, 'No witness nonce present.');
@ -327,9 +327,7 @@ Block.prototype.createCommitmentHash = function createCommitmentHash(enc) {
// Note: malleation check ignored here.
// assert(!malleated);
data = util.concat(root, nonce);
hash = digest.hash256(data);
hash = digest.root256(root, nonce);
return enc === 'hex'
? hash.toString('hex')

View File

@ -17,7 +17,6 @@ const consensus = require('../protocol/consensus');
const AbstractBlock = require('./abstractblock');
const Headers = require('./headers');
const DUMMY = Buffer.from([0]);
const POOL = Buffer.allocUnsafe(64);
/**
* Represents a merkle (filtered) block.
@ -200,7 +199,6 @@ MerkleBlock.prototype.extractTree = function extractTree() {
let flags = this.flags;
let totalTX = this.totalTX;
let height = 0;
let data = POOL;
let root;
let width = (height) => {
@ -246,10 +244,7 @@ MerkleBlock.prototype.extractTree = function extractTree() {
right = left;
}
left.copy(data, 0);
right.copy(data, 32);
return digest.hash256(data);
return digest.root256(left, right);
};
if (totalTX === 0)
@ -566,7 +561,6 @@ MerkleBlock.fromMatches = function fromMatches(block, matches) {
let hashes = [];
let totalTX = block.txs.length;
let height = 0;
let data = POOL;
let flags, merkle;
let width = (height) => {
@ -586,10 +580,7 @@ MerkleBlock.fromMatches = function fromMatches(block, matches) {
else
right = left;
left.copy(data, 0);
right.copy(data, 32);
return digest.hash256(data);
return digest.root256(left, right);
};
let traverse = (height, pos, leaves, matches) => {

View File

@ -451,7 +451,7 @@ TX.prototype.signatureHashV0 = function signatureHashV0(index, prev, type) {
// Bitcoind used to return 1 as an error code:
// it ended up being treated like a hash.
if (index >= this.outputs.length)
return util.copy(encoding.ONE_HASH);
return Buffer.from(encoding.ONE_HASH);
}
// Remove all code separators.

View File

@ -131,8 +131,8 @@ SigCache.prototype.verify = function verify(msg, sig, key) {
*/
function SigCacheEntry(sig, key) {
this.sig = util.copy(sig);
this.key = util.copy(key);
this.sig = Buffer.from(sig);
this.key = Buffer.from(key);
}
/**

View File

@ -16,32 +16,6 @@ const nodeUtil = require('util');
const util = exports;
/**
* Clone a buffer.
* @param {Buffer} data
* @returns {Buffer}
*/
util.copy = function copy(data) {
let clone = Buffer.allocUnsafe(data.length);
data.copy(clone, 0, 0, data.length);
return clone;
};
/**
* Concatenate two buffers.
* @param {Buffer} a
* @param {Buffer} b
* @returns {Buffer}
*/
util.concat = function concat(a, b) {
let data = Buffer.allocUnsafe(a.length + b.length);
a.copy(data, 0);
b.copy(data, a.length);
return data;
};
/**
* Return hrtime (shim for browser).
* @param {Array} time
@ -108,6 +82,8 @@ util.revHex = function revHex(data) {
let out = '';
assert(typeof data === 'string');
assert(data.length > 0);
assert(data.length % 2 === 0);
for (let i = 0; i < data.length; i += 2)
out = data.slice(i, i + 2) + out;
@ -769,15 +745,6 @@ util.binaryRemove = function binaryRemove(items, item, compare) {
return true;
};
/**
* Ensure hidden-class mode for object.
* @param {Object} obj
*/
util.fastProp = function fastProp(obj) {
({ __proto__: obj });
};
/**
* Quick test to see if a string is uppercase.
* @param {String} str

View File

@ -28,7 +28,7 @@
"n64": "0.0.11"
},
"optionalDependencies": {
"bcoin-native": "0.0.20",
"bcoin-native": "0.0.21",
"leveldown": "1.7.0-0",
"secp256k1": "3.2.5",
"socket.io": "2.0.1",

View File

@ -12,7 +12,6 @@ const MTX = require('../lib/primitives/mtx');
const MemWallet = require('./util/memwallet');
const Network = require('../lib/protocol/network');
const Output = require('../lib/primitives/output');
const util = require('../lib/utils/util');
const common = require('../lib/blockchain/common');
const opcodes = Script.opcodes;
@ -547,7 +546,7 @@ describe('Chain', function() {
assert(output.script.isCommitment());
commit = util.copy(output.script.get(1));
commit = Buffer.from(output.script.get(1));
commit.fill(0, 10);
output.script.set(1, commit);
output.script.compile();