perf: start using bcoin-native.

This commit is contained in:
Christopher Jeffrey 2016-09-12 13:33:00 -07:00
parent 27ba246027
commit 7f31a41e84
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
11 changed files with 244 additions and 110 deletions

View File

@ -7,6 +7,7 @@
'use strict';
var assert = require('assert');
var native = require('../utils/native');
var BIG_ENDIAN = new Int8Array(Int16Array.of(1).buffer)[0] === 0;
@ -176,6 +177,9 @@ ChaCha20.prototype.getCounter = function getCounter() {
return lo;
};
if (native)
ChaCha20 = native.ChaCha20;
/*
* Helpers
*/
@ -489,6 +493,9 @@ Poly1305.verify = function verify(mac1, mac2) {
return (dif & 1) !== 0;
};
if (native)
Poly1305 = native.Poly1305;
/**
* AEAD (used for bip151)
* @exports AEAD
@ -527,7 +534,7 @@ AEAD.prototype.init = function init(key, iv) {
this.chacha20.encrypt(new Buffer(32));
// Counter should be one.
assert(this.chacha20.state[12] === 1);
assert(this.chacha20.getCounter() === 1);
// Expose for debugging.
this.polyKey = polyKey;

View File

@ -9,6 +9,7 @@
var assert = require('assert');
var random = require('./random');
var native = require('../utils/native');
var nativeCrypto, supersha, hash, aes;
var isBrowser =
@ -17,11 +18,6 @@ var isBrowser =
if (!isBrowser) {
nativeCrypto = require('crypto');
try {
supersha = require('supersha');
} catch (e) {
;
}
} else {
hash = require('hash.js');
aes = require('./aes');
@ -47,6 +43,9 @@ crypto.hash = function _hash(alg, data) {
return nativeCrypto.createHash(alg).update(data).digest();
};
if (native)
crypto.hash = native.hash;
/**
* Hash with ripemd160.
* @param {Buffer} data
@ -74,11 +73,12 @@ crypto.sha1 = function sha1(data) {
*/
crypto.sha256 = function sha256(data) {
if (supersha)
return supersha.sha256(data);
return crypto.hash('sha256', data);
};
if (native)
crypto.sha256 = native.sha256;
/**
* Hash with sha256 and ripemd160 (OP_HASH160).
* @param {Buffer} data
@ -89,6 +89,9 @@ crypto.hash160 = function hash160(data) {
return crypto.ripemd160(crypto.sha256(data));
};
if (native)
crypto.hash160 = native.hash160;
/**
* Hash with sha256 twice (OP_HASH256).
* @param {Buffer} data
@ -96,11 +99,12 @@ crypto.hash160 = function hash160(data) {
*/
crypto.hash256 = function hash256(data) {
if (supersha)
return supersha.hash256(data);
return crypto.sha256(crypto.sha256(data));
};
if (native)
crypto.hash256 = native.hash256;
/**
* Create a sha256 checksum (common in bitcoin).
* @param {Buffer} data
@ -122,6 +126,14 @@ crypto.checksum = function checksum(data) {
crypto.hmac = function hmac(alg, data, salt) {
var hmac;
if (native) {
if (typeof data === 'string')
data = new Buffer(data, 'utf8');
if (typeof salt === 'string')
salt = new Buffer(salt, 'utf8');
return native.hmac(alg, data, salt);
}
if (!nativeCrypto) {
hmac = hash.hmac(hash[alg], salt);
return new Buffer(hmac.update(data).digest());
@ -472,6 +484,9 @@ crypto.buildMerkleTree = function buildMerkleTree(leaves) {
return tree;
};
if (native)
crypto.buildMerkleTree = native.buildMerkleTree;
/**
* Calculate merkle root from leaves.
* @param {Buffer[]} leaves

View File

@ -35,6 +35,8 @@
var utils = require('../utils/utils');
var crypto = require('./crypto');
var native = require('../utils/native');
var U32Array = typeof Uint32Array === 'function' ? Uint32Array : Array;
/**
* Javascript scrypt implementation. Scrypt is
@ -58,6 +60,9 @@ function scrypt(passwd, salt, N, r, p, len, callback) {
if (typeof salt === 'string')
salt = new Buffer(salt, 'utf8');
if (native)
return native.scryptAsync(passwd, salt, N, r, p, len, callback);
if (r * p >= (1 << 30))
return callback(new Error('EFBIG'));
@ -86,8 +91,8 @@ function scrypt(passwd, salt, N, r, p, len, callback) {
}
function salsa20_8(B) {
var B32 = new Array(16);
var x = new Array(16);
var B32 = new U32Array(16);
var x = new U32Array(16);
var i;
for (i = 0; i < 16; i++)

View File

@ -34,6 +34,8 @@
'use strict';
var crypto = require('./crypto');
var native = require('../utils/native');
var U32Array = typeof Uint32Array === 'function' ? Uint32Array : Array;
/**
* Javascript scrypt implementation. Scrypt is
@ -57,6 +59,9 @@ function scrypt(passwd, salt, N, r, p, len) {
if (typeof salt === 'string')
salt = new Buffer(salt, 'utf8');
if (native)
return native.scrypt(passwd, salt, N, r, p, len);
if (r * p >= (1 << 30))
throw new Error('EFBIG');
@ -78,8 +83,8 @@ function scrypt(passwd, salt, N, r, p, len) {
}
function salsa20_8(B) {
var B32 = new Array(16);
var x = new Array(16);
var B32 = new U32Array(16);
var x = new U32Array(16);
var i;
for (i = 0; i < 16; i++)

View File

@ -9,6 +9,8 @@
'use strict';
var native = require('../utils/native');
/**
* Javascript siphash implementation. Used for compact block relay.
* @param {Buffer} data
@ -16,16 +18,17 @@
* @returns {Buffer} uint64le
*/
function siphash(data, key) {
var blocks = Math.ceil(data.length / 8);
function siphash24(data, key, shift) {
var blocks = Math.floor(data.length / 8);
var c0 = U64(0x736f6d65, 0x70736575);
var c1 = U64(0x646f7261, 0x6e646f6d);
var c2 = U64(0x6c796765, 0x6e657261);
var c3 = U64(0x74656462, 0x79746573);
var f0 = U64(blocks << 27, 0);
var f0 = U64(blocks << (shift - 32), 0);
var f1 = U64(0, 0xff);
var k0 = U64.fromRaw(key, 0);
var k1 = U64.fromRaw(key, 8);
var p = 0;
var i, d, v0, v1, v2, v3;
// Init
@ -36,13 +39,38 @@ function siphash(data, key) {
// Blocks
for (i = 0; i < blocks; i++) {
d = U64.fromRaw(data, i * 8);
d = U64.fromRaw(data, p);
p += 8;
v3.xor(d);
sipround(v0, v1, v2, v3);
sipround(v0, v1, v2, v3);
v0.xor(d);
}
switch (data.length & 7) {
case 7:
f0.hi |= data[p + 6] << 16;
case 6:
f0.hi |= data[p + 5] << 8;
case 5:
f0.hi |= data[p + 4] << 0;
case 4:
f0.lo |= data[p + 3] << 24;
case 3:
f0.lo |= data[p + 2] << 16;
case 2:
f0.lo |= data[p + 1] << 8;
case 1:
f0.lo |= data[p + 0] << 0;
if (f0.lo < 0)
f0.lo += 0x100000000;
if (f0.hi < 0)
f0.hi += 0x100000000;
break;
case 0:
break;
}
// Finalization
v3.xor(f0);
sipround(v0, v1, v2, v3);
@ -82,6 +110,19 @@ function sipround(v0, v1, v2, v3) {
v2.rotl(32);
}
function siphash(data, key) {
return siphash24(data, key, 56);
}
function siphash256(data, key) {
return siphash24(data, key, 59);
}
if (native) {
siphash = native.siphash;
siphash256 = native.siphash256;
}
/*
* Helpers
*/
@ -186,7 +227,9 @@ U64.fromRaw = function fromRaw(data, off) {
* Expose
*/
exports = siphash;
exports = siphash256;
exports.siphash = siphash;
exports.siphash256 = siphash256;
exports.U64 = U64;
module.exports = exports;

View File

@ -11,6 +11,9 @@ var constants = require('../protocol/constants');
var assert = require('assert');
var BufferReader = require('../utils/reader');
var BufferWriter = require('../utils/writer');
var murmur3 = require('../utils/murmur3');
var sum32 = murmur3.sum32;
var mul32 = murmur3.mul32;
/*
* Constants
@ -408,94 +411,10 @@ RollingFilter.prototype.added = function added(val, enc) {
return false;
};
/**
* Murmur3 hash.
* @memberof Bloom
* @param {Buffer} data
* @param {Number} seed
* @returns {Number}
/*
* Helpers
*/
function murmur3(data, seed) {
var tail = data.length - (data.length % 4);
var c1 = 0xcc9e2d51;
var c2 = 0x1b873593;
var h1 = seed;
var i, k1;
for (i = 0; i < tail; i += 4) {
k1 = (data[i + 3] << 24)
| (data[i + 2] << 16)
| (data[i + 1] << 8)
| data[i];
k1 = mul32(k1, c1);
k1 = rotl32(k1, 15);
k1 = mul32(k1, c2);
h1 ^= k1;
h1 = rotl32(h1, 13);
h1 = sum32(mul32(h1, 5), 0xe6546b64);
}
k1 = 0;
switch (data.length & 3) {
case 3:
k1 ^= data[tail + 2] << 16;
case 2:
k1 ^= data[tail + 1] << 8;
case 1:
k1 ^= data[tail + 0];
k1 = mul32(k1, c1);
k1 = rotl32(k1, 15);
k1 = mul32(k1, c2);
h1 ^= k1;
}
h1 ^= data.length;
h1 ^= h1 >>> 16;
h1 = mul32(h1, 0x85ebca6b);
h1 ^= h1 >>> 13;
h1 = mul32(h1, 0xc2b2ae35);
h1 ^= h1 >>> 16;
if (h1 < 0)
h1 += 0x100000000;
return h1;
}
function mul32(a, b) {
var alo = a & 0xffff;
var blo = b & 0xffff;
var ahi = a >>> 16;
var bhi = b >>> 16;
var r, lo, hi;
lo = alo * blo;
hi = (ahi * blo + bhi * alo) & 0xffff;
hi += lo >>> 16;
lo &= 0xffff;
r = (hi << 16) | lo;
if (r < 0)
r += 0x100000000;
return r;
}
function sum32(a, b) {
var r = (a + b) & 0xffffffff;
if (r < 0)
r += 0x100000000;
return r;
}
function rotl32(w, b) {
return (w << b) | (w >>> (32 - b));
}
function read(data, off) {
return {
hi: data.readUInt32LE(off + 4, true),

112
lib/utils/murmur3.js Normal file
View File

@ -0,0 +1,112 @@
/*!
* murmur3.js - murmur3 hash for bcoin
* Copyright (c) 2014-2015, Fedor Indutny (MIT License)
* Copyright (c) 2014-2016, Christopher Jeffrey (MIT License).
* https://github.com/bcoin-org/bcoin
*/
'use strict';
var native = require('./native');
/**
* Murmur3 hash.
* @memberof Bloom
* @param {Buffer} data
* @param {Number} seed
* @returns {Number}
*/
function murmur3(data, seed) {
var tail = data.length - (data.length % 4);
var c1 = 0xcc9e2d51;
var c2 = 0x1b873593;
var h1 = seed;
var i, k1;
for (i = 0; i < tail; i += 4) {
k1 = (data[i + 3] << 24)
| (data[i + 2] << 16)
| (data[i + 1] << 8)
| data[i];
k1 = mul32(k1, c1);
k1 = rotl32(k1, 15);
k1 = mul32(k1, c2);
h1 ^= k1;
h1 = rotl32(h1, 13);
h1 = sum32(mul32(h1, 5), 0xe6546b64);
}
k1 = 0;
switch (data.length & 3) {
case 3:
k1 ^= data[tail + 2] << 16;
case 2:
k1 ^= data[tail + 1] << 8;
case 1:
k1 ^= data[tail + 0];
k1 = mul32(k1, c1);
k1 = rotl32(k1, 15);
k1 = mul32(k1, c2);
h1 ^= k1;
}
h1 ^= data.length;
h1 ^= h1 >>> 16;
h1 = mul32(h1, 0x85ebca6b);
h1 ^= h1 >>> 13;
h1 = mul32(h1, 0xc2b2ae35);
h1 ^= h1 >>> 16;
if (h1 < 0)
h1 += 0x100000000;
return h1;
}
if (native)
murmur3 = native.murmur3;
function mul32(a, b) {
var alo = a & 0xffff;
var blo = b & 0xffff;
var ahi = a >>> 16;
var bhi = b >>> 16;
var r, lo, hi;
lo = alo * blo;
hi = (ahi * blo + bhi * alo) & 0xffff;
hi += lo >>> 16;
lo &= 0xffff;
r = (hi << 16) | lo;
if (r < 0)
r += 0x100000000;
return r;
}
function sum32(a, b) {
var r = (a + b) & 0xffffffff;
if (r < 0)
r += 0x100000000;
return r;
}
function rotl32(w, b) {
return (w << b) | (w >>> (32 - b));
}
/**
* Expose
*/
exports = murmur3;
exports.murmur3 = murmur3;
exports.mul32 = mul32;
exports.sum32 = sum32;
exports.rotl32 = rotl32;
module.exports = exports;

21
lib/utils/native.js Normal file
View File

@ -0,0 +1,21 @@
/*!
* native.js - native bindings for bcoin
* Copyright (c) 2016, Christopher Jeffrey (MIT License).
* https://github.com/bcoin-org/bcoin
*/
'use strict';
var isBrowser =
(typeof process !== 'undefined' && process.browser)
|| typeof window !== 'undefined';
module.exports = null;
if (!isBrowser && +process.env.BCOIN_NO_NATIVE !== 1) {
try {
module.exports = require('bcoin-native');
} catch (e) {
;
}
}

View File

@ -16,6 +16,7 @@
var utils = exports;
var assert = require('assert');
var native = require('./native');
var bn = require('bn.js');
var util = require('util');
var Number, Math, Date;
@ -165,6 +166,9 @@ utils.toBase58 = function toBase58(data) {
return str;
};
if (native)
utils.toBase58 = native.toBase58;
/**
* Decode a base58 string.
* @see https://github.com/bitcoin/bitcoin/blob/master/src/base58.cpp
@ -217,6 +221,9 @@ utils.fromBase58 = function fromBase58(str) {
return out;
};
if (native)
utils.fromBase58 = native.fromBase58;
/**
* Test whether a string is base58 (note that you
* may get a false positive on a hex string).

View File

@ -40,11 +40,11 @@
"elliptic": "6.3.1"
},
"optionalDependencies": {
"bcoin-native": "0.0.2",
"leveldown": "git://github.com/Level/leveldown.git#leveldb-1.19",
"secp256k1": "3.2.0",
"socket.io": "1.4.8",
"socket.io-client": "1.4.8",
"supersha": "0.0.1"
"socket.io-client": "1.4.8"
},
"devDependencies": {
"browserify": "13.1.0",
@ -67,7 +67,7 @@
"child_process": "./browser/empty.js",
"os": "./browser/empty.js",
"net": "./browser/empty.js",
"supersha": "./browser/empty.js",
"bcoin-native": "./browser/empty.js",
"secp256k1": "./browser/empty.js"
}
}

View File

@ -50,7 +50,7 @@ describe('ChaCha20 / Poly1305 / AEAD', function() {
var aead = new AEAD();
aead.init(key, nonce);
assert.equal(aead.chacha20.state[12], 1);
assert.equal(aead.chacha20.getCounter(), 1);
assert.deepEqual(aead.polyKey, pk);
aead.aad(aad);
var plainenc = new Buffer(plain);
@ -60,7 +60,7 @@ describe('ChaCha20 / Poly1305 / AEAD', function() {
var aead = new AEAD();
aead.init(key, nonce);
assert.equal(aead.chacha20.state[12], 1);
assert.equal(aead.chacha20.getCounter(), 1);
assert.deepEqual(aead.polyKey, pk);
aead.aad(aad);
aead.decrypt(ciphertext);