@gohelpfund/x11-hash-js
Version: 
x11 javascript hashing algorithm in pure javascript
368 lines (329 loc) • 12.8 kB
JavaScript
'use strict';
/////////////////////////////////////
//////////////  BMW /////////////////
//// Written by Quantum Explorer ////
////////// Dash Foundation //////////
/// Released under the MIT License //
/////////////////////////////////////
var o = require('./op');
var h = require('./helper');
// var V_INIT = [
//   o.u(0x80818283, 0x84858687), o.u(0x88898A8B, 0x8C8D8E8F),
//   o.u(0x90919293, 0x94959697), o.u(0x98999A9B, 0x9C9D9E9F),
//   o.u(0xA0A1A2A3, 0xA4A5A6A7), o.u(0xA8A9AAAB, 0xACADAEAF),
//   o.u(0xB0B1B2B3, 0xB4B5B6B7), o.u(0xB8B9BABB, 0xBCBDBEBF),
//   o.u(0xC0C1C2C3, 0xC4C5C6C7), o.u(0xC8C9CACB, 0xCCCDCECF),
//   o.u(0xD0D1D2D3, 0xD4D5D6D7), o.u(0xD8D9DADB, 0xDCDDDEDF),
//   o.u(0xE0E1E2E3, 0xE4E5E6E7), o.u(0xE8E9EAEB, 0xECEDEEEF),
//   o.u(0xF0F1F2F3, 0xF4F5F6F7), o.u(0xF8F9FAFB, 0xFCFDFEFF)
// ];
var V_INIT = h.bytes2Int64Buffer(h.b64Decode('gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp+goaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DBwsPExcbHyMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3+Pn6+/z9/v8='));
// var final = [
//   o.u(0xaaaaaaaa, 0xaaaaaaa0), o.u(0xaaaaaaaa, 0xaaaaaaa1),
//   o.u(0xaaaaaaaa, 0xaaaaaaa2), o.u(0xaaaaaaaa, 0xaaaaaaa3),
//   o.u(0xaaaaaaaa, 0xaaaaaaa4), o.u(0xaaaaaaaa, 0xaaaaaaa5),
//   o.u(0xaaaaaaaa, 0xaaaaaaa6), o.u(0xaaaaaaaa, 0xaaaaaaa7),
//   o.u(0xaaaaaaaa, 0xaaaaaaa8), o.u(0xaaaaaaaa, 0xaaaaaaa9),
//   o.u(0xaaaaaaaa, 0xaaaaaaaa), o.u(0xaaaaaaaa, 0xaaaaaaab),
//   o.u(0xaaaaaaaa, 0xaaaaaaac), o.u(0xaaaaaaaa, 0xaaaaaaad),
//   o.u(0xaaaaaaaa, 0xaaaaaaae), o.u(0xaaaaaaaa, 0xaaaaaaaf)
// ];
var final = h.bytes2Int64Buffer(h.b64Decode('qqqqqqqqqqCqqqqqqqqqoaqqqqqqqqqiqqqqqqqqqqOqqqqqqqqqpKqqqqqqqqqlqqqqqqqqqqaqqqqqqqqqp6qqqqqqqqqoqqqqqqqqqqmqqqqqqqqqqqqqqqqqqqqrqqqqqqqqqqyqqqqqqqqqraqqqqqqqqquqqqqqqqqqq8='));
var sb_a = [1, 1, 2, 2, 1, 2];
var sb_b = [3, 2, 1, 2];
var sb_c = [4, 13, 19, 28];
var sb_d = [37, 43, 53, 59];
var I16 = new Array(16); //we are trying to start at 16;
I16.push([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]);
I16.push([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
I16.push([2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]);
I16.push([3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]);
I16.push([4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]);
I16.push([5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]);
I16.push([6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21]);
I16.push([7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22]);
I16.push([8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23]);
I16.push([9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]);
I16.push([10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]);
I16.push([11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26]);
I16.push([12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27]);
I16.push([13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28]);
I16.push([14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]);
I16.push([15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]);
var M16 = new Array(16);
M16.push([0, 1, 3, 4, 7, 10, 11]);
M16.push([1, 2, 4, 5, 8, 11, 12]);
M16.push([2, 3, 5, 6, 9, 12, 13]);
M16.push([3, 4, 6, 7, 10, 13, 14]);
M16.push([4, 5, 7, 8, 11, 14, 15]);
M16.push([5, 6, 8, 9, 12, 15, 16]);
M16.push([6, 7, 9, 10, 13, 0, 1]);
M16.push([7, 8, 10, 11, 14, 1, 2]);
M16.push([8, 9, 11, 12, 15, 2, 3]);
M16.push([9, 10, 12, 13, 0, 3, 4]);
M16.push([10, 11, 13, 14, 1, 4, 5]);
M16.push([11, 12, 14, 15, 2, 5, 6]);
M16.push([12, 13, 15, 16, 3, 6, 7]);
M16.push([13, 14, 0, 1, 4, 7, 8]);
M16.push([14, 15, 1, 2, 5, 8, 9]);
M16.push([15, 16, 2, 3, 6, 9, 10]);
var sb = function(n, x) {
    //xOriginal must be of type u64
    if (n < 4) {
        return o.xor64(x.shiftRight(sb_a[n]), x.shiftLeft(sb_b[n]), x.rotateLeft(sb_c[n]), x.rotateLeft(sb_d[n]));
    }
    return x.shiftRight(sb_a[n]).xor(x);
};
var rbn = [0, 5, 11, 27, 32, 37, 43, 53];
var rb = function(n, x) {
    //x must be of type u64
    return x.rotateLeft(rbn[n]);
};
var makeW = function(M,H,i, op) {
    var a = M[i[0]].xor(H[i[0]]);
    var b = M[i[1]].xor(H[i[1]]);
    var c = M[i[2]].xor(H[i[2]]);
    var d = M[i[3]].xor(H[i[3]]);
    var e = M[i[4]].xor(H[i[4]]);
    var w = op[3](op[2](op[1](op[0](a,b),c),d),e);
    return w;
};
var wbn = [
    [5, 7, 10, 13, 14],
    [6, 8, 11, 14, 15],
    [0, 7, 9, 12, 15],
    [0, 1, 8, 10, 13],
    [1, 2, 9, 11, 14],
    [3, 2, 10, 12, 15],
    [4, 0, 3, 11, 13],
    [1, 4, 5, 12, 14],
    [2, 5, 6, 13, 15],
    [0, 3, 6, 7, 14],
    [8, 1, 4, 7, 15],
    [8, 0, 2, 5, 9],
    [1, 3, 6, 9, 10],
    [2, 4, 7, 10, 11],
    [3, 5, 8, 11, 12],
    [12, 4, 6, 9, 13],
];
var plus = function(a,b) {
    return a.plus(b);
};
var minus = function(a,b) {
    return a.minus(b);
};
var wboperators = [
    [minus, plus, plus, plus],
    [minus, plus, plus, minus],
    [plus, plus, minus, plus],
    [minus, plus, minus, plus],
    [plus, plus, minus, minus],
    [minus, plus, minus, plus],
    [minus, minus, minus, plus],
    [minus, minus, minus, minus],
    [minus, minus, plus, minus],
    [minus, plus, minus, plus],
    [minus, minus, minus, plus],
    [minus, minus, minus, plus],
    [plus, minus, minus, plus],
    [plus, plus, plus, plus],
    [minus, plus, minus, minus],
    [minus, minus, minus, plus],
];
var wb = function(M,H,i) {
    return makeW(M,H,wbn[i],wboperators[i]);
};
var kb = function(j) {
    var fives = o.u(0x05555555, 0x55555555);
    return fives.multiply(j);
};
var addElt = function(buffer64, state, mVars, i) {
    var k = kb(i);
    var elt = buffer64[mVars[0]].rotateLeft(mVars[1])
        .add(buffer64[mVars[2]].rotateLeft(mVars[3]))
        .minus(buffer64[mVars[5]].rotateLeft(mVars[6]))
        .add(k)
        .xor(state[mVars[4]]);
    return elt;
};
var expand2Inner = function(qt, mf, state, i, iVars, mVars) {
    return qt[iVars[0]]
        .plus(rb(1, qt[iVars[1]]))
        .add(qt[iVars[2]])
        .add(rb(2, qt[iVars[3]]))
        .add(qt[iVars[4]])
        .add(rb(3, qt[iVars[5]]))
        .add(qt[iVars[6]])
        .add(rb(4, qt[iVars[7]]))
        .add(qt[iVars[8]])
        .add(rb(5, qt[iVars[9]]))
        .add(qt[iVars[10]])
        .add(rb(6, qt[iVars[11]]))
        .add(qt[iVars[12]])
        .add(rb(7, qt[iVars[13]]))
        .add(sb(4, qt[iVars[14]]))
        .add(sb(5, qt[iVars[15]]))
        .add(addElt(mf, state, mVars, i));
};
var expand1Inner = function(qt, mf, state, i, iVars, mVars) {
    return sb(1, qt[iVars[0]])
        .add(sb(2, qt[iVars[1]]))
        .add(sb(3, qt[iVars[2]]))
        .add(sb(0, qt[iVars[3]]))
        .add(sb(1, qt[iVars[4]]))
        .add(sb(2, qt[iVars[5]]))
        .add(sb(3, qt[iVars[6]]))
        .add(sb(0, qt[iVars[7]]))
        .add(sb(1, qt[iVars[8]]))
        .add(sb(2, qt[iVars[9]]))
        .add(sb(3, qt[iVars[10]]))
        .add(sb(0, qt[iVars[11]]))
        .add(sb(1, qt[iVars[12]]))
        .add(sb(2, qt[iVars[13]]))
        .add(sb(3, qt[iVars[14]]))
        .add(sb(0, qt[iVars[15]]))
        .add(addElt(mf, state, mVars, i));
};
var expand1b = function(qt, mf, state, i) {
    var iVars = I16[i];
    var mVars = M16[i];
    return expand1Inner(qt, mf, state, i, iVars, mVars);
};
var expand2b = function(qt, mf, state, i) {
    var iVars = I16[i];
    var mVars = M16[i];
    return expand2Inner(qt, mf, state, i, iVars, mVars);
};
var makeQ = function(mf, state) {
    var qt = new Array(32);
    for (var i = 0; i < 16; i++) {
        var w = wb(mf,state,i);
        var s = sb(i % 5, w);
        qt[i] = s.plus(state[(i + 1) % 16]);
    }
    qt[16] = expand1b(qt, mf, state, 16);
    qt[17] = expand1b(qt, mf, state, 17);
    for (var i = 18; i < 32; i++) {
        qt[i] = expand2b(qt, mf, state, i);
    }
    return qt;
};
var fold = function(int64Buffer, state) {
    var out = new Array(16);
    var qt = makeQ(int64Buffer, state);
    var xl = o.xor64(qt[16], qt[17], qt[18], qt[19], qt[20], qt[21], qt[22], qt[23]);
    var xh = o.xor64(xl, qt[24], qt[25], qt[26], qt[27], qt[28], qt[29], qt[30], qt[31]);
    out[0] = o.xor64(xh.shiftLeft(5), qt[16].shiftRight(5), int64Buffer[0]).add(o.xor64(xl, qt[24], qt[0]));
    out[1] = o.xor64(xh.shiftRight(7), qt[17].shiftLeft(8), int64Buffer[1]).add(o.xor64(xl, qt[25], qt[1]));
    out[2] = o.xor64(xh.shiftRight(5), qt[18].shiftLeft(5), int64Buffer[2]).add(o.xor64(xl, qt[26], qt[2]));
    out[3] = o.xor64(xh.shiftRight(1), qt[19].shiftLeft(5), int64Buffer[3]).add(o.xor64(xl, qt[27], qt[3]));
    out[4] = o.xor64(xh.shiftRight(3), qt[20], int64Buffer[4]).add(o.xor64(xl, qt[28], qt[4]));
    out[5] = o.xor64(xh.shiftLeft(6), qt[21].shiftRight(6), int64Buffer[5]).add(o.xor64(xl, qt[29], qt[5]));
    out[6] = o.xor64(xh.shiftRight(4), qt[22].shiftLeft(6), int64Buffer[6]).add(o.xor64(xl, qt[30], qt[6]));
    out[7] = o.xor64(xh.shiftRight(11), qt[23].shiftLeft(2), int64Buffer[7]).add(o.xor64(xl, qt[31], qt[7]));
    out[8] = out[4].rotateLeft(9).add(o.xor64(xh, qt[24], int64Buffer[8]))
        .add(o.xor64(xl.shiftLeft(8), qt[23], qt[8]));
    out[9] = out[5].rotateLeft(10).add(o.xor64(xh, qt[25], int64Buffer[9]))
        .add(o.xor64(xl.shiftRight(6), qt[16], qt[9]));
    out[10] = out[6].rotateLeft(11).add(o.xor64(xh, qt[26], int64Buffer[10]))
        .add(o.xor64(xl.shiftLeft(6), qt[17], qt[10]));
    out[11] = out[7].rotateLeft(12).add(o.xor64(xh, qt[27], int64Buffer[11]))
        .add(o.xor64(xl.shiftLeft(4), qt[18], qt[11]));
    out[12] = out[0].rotateLeft(13).add(o.xor64(xh, qt[28], int64Buffer[12]))
        .add(o.xor64(xl.shiftRight(3), qt[19], qt[12]));
    out[13] = out[1].rotateLeft(14).add(o.xor64(xh, qt[29], int64Buffer[13]))
        .add(o.xor64(xl.shiftRight(4), qt[20], qt[13]));
    out[14] = out[2].rotateLeft(15).add(o.xor64(xh, qt[30], int64Buffer[14]))
        .add(o.xor64(xl.shiftRight(7), qt[21], qt[14]));
    out[15] = out[3].rotateLeft(16).add(o.xor64(xh, qt[31], int64Buffer[15]))
        .add(o.xor64(xl.shiftRight(2), qt[22], qt[15]));
    return out;
};
var compress = function(buf, state) {
    var int64Buf = h.bytes2Int64BufferLeAligned(buf);
    return fold(int64Buf, state);
};
var bmw = function(ctx, data) {
    var htmp = new Array(16);
    var len = data.length;
    var lenL3 = o.u(0, len);
    lenL3 = lenL3.shiftLeft(3);
    ctx.bitCount.add(lenL3);
    var buf = ctx.buffer;
    var ptr = ctx.ptr;
    var h1 = ctx.state;
    var h2 = htmp;
    while (len > 0) {
        var clen = ctx.buffer.length - ptr;
        if (clen > len) clen = len;
        o.bufferInsert(buf, ptr, data, clen);
        data = data.slice(clen);
        len -= clen;
        ptr += clen;
        if (ptr === ctx.buffer.length) {
            var ht;
            h2 = compress(buf, h1);
            ht = h1;
            h1 = h2;
            h2 = ht;
            ptr = 0;
        }
    }
    ctx.ptr = ptr;
    if (h1 !== ctx.state) o.bufferInsert(ctx.state, 0, h1, ctx.state.length);
};
var bmwClose = function(ctx) {
    var h1;
    var h2 = new Array(16);
    var buf = ctx.buffer;
    var ptr = ctx.ptr;
    var len = buf.length;
    buf[ptr++] = 0x80;
    var hState = ctx.state;
    if (ptr > len - 8) {
        o.bufferSet(buf, ptr, 0, len - ptr);
        hState = compress(buf, hState);
        ptr = 0;
    }
    o.bufferSet(buf, ptr, 0, len - 8 - ptr);
    h.bufferEncode64leAligned(buf, len - 8, ctx.bitCount);
    h2 = compress(buf, hState);
    for (u = 0; u < 16; u++) h.bufferEncode64leAligned(buf, 8 * u, h2[u]);
    h1 = compress(buf, final);
    var out = new Array(16);
    for (var u = 0, v = 8; u < 8; u++, v++) {
        out[2 * u] = o.swap32(h1[v].lo);
        out[2 * u + 1] = o.swap32(h1[v].hi);
    }
    return out;
};
module.exports = function(input, format, output) {
    var msg;
    if (format === 1) {
        msg = input;
    }
    else if (format === 2) {
        msg = h.int32Buffer2Bytes(input);
    }
    else {
        msg = h.string2bytes(input);
    }
    var ctx = {};
    ctx.state = o.clone64Array(V_INIT);
    ctx.ptr = 0;
    ctx.bitCount = o.u(0,0);
    ctx.buffer = new Array(128);
    bmw(ctx, msg);
    var r = bmwClose(ctx, 0, 0);
    var out;
    if (output === 2) {
        out = r;
    }
    else if (output === 1) {
        out = h.int32Buffer2Bytes(r);
    }
    else {
        out = h.int32ArrayToHexString(r);
    }
    return out;
};