diff --git a/lib/crypto/siphash.js b/lib/crypto/siphash.js index 08b5c4b3..8f45f575 100644 --- a/lib/crypto/siphash.js +++ b/lib/crypto/siphash.js @@ -16,14 +16,15 @@ const native = require('../native').binding; /** - * Javascript siphash implementation. Used for compact block relay. - * @alias module:crypto/siphash.siphash24 + * Javascript siphash 2-4 implementation. + * @private * @param {Buffer} data * @param {Buffer} key - 128 bit key. + * @param {Number} shift * @returns {Array} [hi, lo] */ -function siphash24(data, key, shift) { +function _siphash(data, key, shift) { const blocks = Math.floor(data.length / 8); const c0 = U64(0x736f6d65, 0x70736575); const c1 = U64(0x646f7261, 0x6e646f6d); @@ -85,30 +86,50 @@ function siphash24(data, key, shift) { return [v0.hi, v0.lo]; } -function sipround(v0, v1, v2, v3) { - v0.iadd(v1); - v1.irotl(13); - v1.ixor(v0); +/** + * Javascript siphash 2-4 implementation (64 bit ints). + * @private + * @param {Number} hi + * @param {Number} lo + * @param {Buffer} key - 128 bit key. + * @returns {Array} [hi, lo] + */ - v0.irotl(32); +function _siphash64(hi, lo, key) { + const c0 = U64(0x736f6d65, 0x70736575); + const c1 = U64(0x646f7261, 0x6e646f6d); + const c2 = U64(0x6c796765, 0x6e657261); + const c3 = U64(0x74656462, 0x79746573); + const f0 = U64(hi, lo); + const f1 = U64(0, 0xff); + const k0 = U64.fromRaw(key, 0); + const k1 = U64.fromRaw(key, 8); - v2.iadd(v3); - v3.irotl(16); - v3.ixor(v2); + // Init + const v0 = c0.ixor(k0); + const v1 = c1.ixor(k1); + const v2 = c2.ixor(k0); + const v3 = c3.ixor(k1); - v0.iadd(v3); - v3.irotl(21); - v3.ixor(v0); + // Finalization + v3.ixor(f0); + sipround(v0, v1, v2, v3); + sipround(v0, v1, v2, v3); + v0.ixor(f0); + v2.ixor(f1); + sipround(v0, v1, v2, v3); + sipround(v0, v1, v2, v3); + sipround(v0, v1, v2, v3); + sipround(v0, v1, v2, v3); + v0.ixor(v1); + v0.ixor(v2); + v0.ixor(v3); - v2.iadd(v1); - v1.irotl(17); - v1.ixor(v2); - - v2.irotl(32); + return [v0.hi, v0.lo]; } /** - * Javascript siphash implementation (shift=56). + * Javascript siphash 2-4 implementation (shift=56). * @alias module:crypto/siphash.siphash * @param {Buffer} data * @param {Buffer} key - 128 bit key. @@ -116,11 +137,11 @@ function sipround(v0, v1, v2, v3) { */ function siphash(data, key) { - return siphash24(data, key, 56); + return _siphash(data, key, 56); } /** - * Javascript siphash implementation (shift=59). + * Javascript siphash 2-4 implementation (shift=59). * @alias module:crypto/siphash.siphash256 * @param {Buffer} data * @param {Buffer} key - 128 bit key. @@ -128,12 +149,39 @@ function siphash(data, key) { */ function siphash256(data, key) { - return siphash24(data, key, 59); + return _siphash(data, key, 59); +} + +/** + * Javascript siphash 2-4 implementation (32 bit ints). + * @alias module:crypto/siphash.siphash32 + * @param {Number} num + * @param {Buffer} key - 128 bit key. + * @returns {Number} + */ + +function siphash32(num, key) { + return _siphash64(0, num, key)[1]; +} + +/** + * Javascript siphash 2-4 implementation (64 bit ints). + * @alias module:crypto/siphash.siphash64 + * @param {Number} hi + * @param {Number} lo + * @param {Buffer} key - 128 bit key. + * @returns {Array} [hi, lo] + */ + +function siphash64(hi, lo, key) { + return _siphash64(hi, lo, key); } if (native) { siphash = native.siphash; siphash256 = native.siphash256; + siphash32 = native.siphash32; + siphash64 = native.siphash64; } /* @@ -217,6 +265,32 @@ U64.fromRaw = function fromRaw(data, off) { return new U64(hi, lo); }; +/* + * Helpers + */ + +function sipround(v0, v1, v2, v3) { + v0.iadd(v1); + v1.irotl(13); + v1.ixor(v0); + + v0.irotl(32); + + v2.iadd(v3); + v3.irotl(16); + v3.ixor(v2); + + v0.iadd(v3); + v3.irotl(21); + v3.ixor(v0); + + v2.iadd(v1); + v1.irotl(17); + v1.ixor(v2); + + v2.irotl(32); +} + /* * Expose */ @@ -224,5 +298,7 @@ U64.fromRaw = function fromRaw(data, off) { exports = siphash; exports.siphash = siphash; exports.siphash256 = siphash256; +exports.siphash32 = siphash32; +exports.siphash64 = siphash64; module.exports = exports;