@gohelpfund/x11-hash-js
Version: 
x11 javascript hashing algorithm in pure javascript
476 lines (436 loc) • 15.6 kB
JavaScript
'use strict';
/////////////////////////////////////
//////////////  Simd ///////////////
//// Written by Quantum Explorer ////
////////// Dash Foundation //////////
/// Released under the MIT License //
/////////////////////////////////////
var op = require('./op');
var h = require('./helper');
var IV512 = h.bytes2Int32Buffer(h.b64Decode('C6FrlXL5ma2f7MKuujJk/F6JSSmOnzDlLx2qN/DyxVisUGZDqQY1peJbh4uqt4ePiIF/egoCiStVmnVQWY9lfn7vYKFrcOPonBcU0blY4qirAmde7RwBT82NZbv9t6JXCSVImdaZx7yQGbbcK5Ai5I+hSVYhv5vTuU0JQ2/93CI='));
// var IV512 = [
//   0x0BA16B95, 0x72F999AD, 0x9FECC2AE, 0xBA3264FC,
//   0x5E894929, 0x8E9F30E5, 0x2F1DAA37, 0xF0F2C558,
//   0xAC506643, 0xA90635A5, 0xE25B878B, 0xAAB7878F,
//   0x88817F7A, 0x0A02892B, 0x559A7550, 0x598F657E,
//   0x7EEF60A1, 0x6B70E3E8, 0x9C1714D1, 0xB958E2A8,
//   0xAB02675E, 0xED1C014F, 0xCD8D65BB, 0xFDB7A257,
//   0x09254899, 0xD699C7BC, 0x9019B6DC, 0x2B9022E4,
//   0x8FA14956, 0x21BF9BD3, 0xB94D0943, 0x6FFDDC22,
// ];
/*
 * The powers of 41 modulo 257. We use exponents from 0 to 255, inclusive.
 */
var alpha_tab = [
    1, 41, 139, 45, 46, 87, 226, 14, 60, 147, 116, 130,
    190, 80, 196, 69, 2, 82, 21, 90, 92, 174, 195, 28,
    120, 37, 232, 3, 123, 160, 135, 138, 4, 164, 42, 180,
    184, 91, 133, 56, 240, 74, 207, 6, 246, 63, 13, 19,
    8, 71, 84, 103, 111, 182, 9, 112, 223, 148, 157, 12,
    235, 126, 26, 38, 16, 142, 168, 206, 222, 107, 18, 224,
    189, 39, 57, 24, 213, 252, 52, 76, 32, 27, 79, 155,
    187, 214, 36, 191, 121, 78, 114, 48, 169, 247, 104, 152,
    64, 54, 158, 53, 117, 171, 72, 125, 242, 156, 228, 96,
    81, 237, 208, 47, 128, 108, 59, 106, 234, 85, 144, 250,
    227, 55, 199, 192, 162, 217, 159, 94, 256, 216, 118, 212,
    211, 170, 31, 243, 197, 110, 141, 127, 67, 177, 61, 188,
    255, 175, 236, 167, 165, 83, 62, 229, 137, 220, 25, 254,
    134, 97, 122, 119, 253, 93, 215, 77, 73, 166, 124, 201,
    17, 183, 50, 251, 11, 194, 244, 238, 249, 186, 173, 154,
    146, 75, 248, 145, 34, 109, 100, 245, 22, 131, 231, 219,
    241, 115, 89, 51, 35, 150, 239, 33, 68, 218, 200, 233,
    44, 5, 205, 181, 225, 230, 178, 102, 70, 43, 221, 66,
    136, 179, 143, 209, 88, 10, 153, 105, 193, 203, 99, 204,
    140, 86, 185, 132, 15, 101, 29, 161, 176, 20, 49, 210,
    129, 149, 198, 151, 23, 172, 113, 7, 30, 202, 58, 65,
    95, 40, 98, 163
];
// console.log(alpha_tab);
//console.log(h.b64Encode(alpha_tab));
/*
 * beta^(255*i) mod 257
 */
var yoff_b_n = [
    1, 163, 98, 40, 95, 65, 58, 202, 30, 7, 113, 172,
    23, 151, 198, 149, 129, 210, 49, 20, 176, 161, 29, 101,
    15, 132, 185, 86, 140, 204, 99, 203, 193, 105, 153, 10,
    88, 209, 143, 179, 136, 66, 221, 43, 70, 102, 178, 230,
    225, 181, 205, 5, 44, 233, 200, 218, 68, 33, 239, 150,
    35, 51, 89, 115, 241, 219, 231, 131, 22, 245, 100, 109,
    34, 145, 248, 75, 146, 154, 173, 186, 249, 238, 244, 194,
    11, 251, 50, 183, 17, 201, 124, 166, 73, 77, 215, 93,
    253, 119, 122, 97, 134, 254, 25, 220, 137, 229, 62, 83,
    165, 167, 236, 175, 255, 188, 61, 177, 67, 127, 141, 110,
    197, 243, 31, 170, 211, 212, 118, 216, 256, 94, 159, 217,
    162, 192, 199, 55, 227, 250, 144, 85, 234, 106, 59, 108,
    128, 47, 208, 237, 81, 96, 228, 156, 242, 125, 72, 171,
    117, 53, 158, 54, 64, 152, 104, 247, 169, 48, 114, 78,
    121, 191, 36, 214, 187, 155, 79, 27, 32, 76, 52, 252,
    213, 24, 57, 39, 189, 224, 18, 107, 222, 206, 168, 142,
    16, 38, 26, 126, 235, 12, 157, 148, 223, 112, 9, 182,
    111, 103, 84, 71, 8, 19, 13, 63, 246, 6, 207, 74,
    240, 56, 133, 91, 184, 180, 42, 164, 4, 138, 135, 160,
    123, 3, 232, 37, 120, 28, 195, 174, 92, 90, 21, 82,
    2, 69, 196, 80, 190, 130, 116, 147, 60, 14, 226, 87,
    46, 45, 139, 41
];
/*
 * beta^(255*i) + beta^(253*i) mod 257
 */
var yoff_b_f = [
    2, 203, 156, 47, 118, 214, 107, 106, 45, 93, 212, 20,
    111, 73, 162, 251, 97, 215, 249, 53, 211, 19, 3, 89,
    49, 207, 101, 67, 151, 130, 223, 23, 189, 202, 178, 239,
    253, 127, 204, 49, 76, 236, 82, 137, 232, 157, 65, 79,
    96, 161, 176, 130, 161, 30, 47, 9, 189, 247, 61, 226,
    248, 90, 107, 64, 0, 88, 131, 243, 133, 59, 113, 115,
    17, 236, 33, 213, 12, 191, 111, 19, 251, 61, 103, 208,
    57, 35, 148, 248, 47, 116, 65, 119, 249, 178, 143, 40,
    189, 129, 8, 163, 204, 227, 230, 196, 205, 122, 151, 45,
    187, 19, 227, 72, 247, 125, 111, 121, 140, 220, 6, 107,
    77, 69, 10, 101, 21, 65, 149, 171, 255, 54, 101, 210,
    139, 43, 150, 151, 212, 164, 45, 237, 146, 184, 95, 6,
    160, 42, 8, 204, 46, 238, 254, 168, 208, 50, 156, 190,
    106, 127, 34, 234, 68, 55, 79, 18, 4, 130, 53, 208,
    181, 21, 175, 120, 25, 100, 192, 178, 161, 96, 81, 127,
    96, 227, 210, 248, 68, 10, 196, 31, 9, 167, 150, 193,
    0, 169, 126, 14, 124, 198, 144, 142, 240, 21, 224, 44,
    245, 66, 146, 238, 6, 196, 154, 49, 200, 222, 109, 9,
    210, 141, 192, 138, 8, 79, 114, 217, 68, 128, 249, 94,
    53, 30, 27, 61, 52, 135, 106, 212, 70, 238, 30, 185,
    10, 132, 146, 136, 117, 37, 251, 150, 180, 188, 247, 156,
    236, 192, 108, 86
];
var WB_DATA = [
    [
        [4, 0, 1, 185],
        [6, 0, 1, 185],
        [0, 0, 1, 185],
        [2, 0, 1, 185],
        [7, 0, 1, 185],
        [5, 0, 1, 185],
        [3, 0, 1, 185],
        [1, 0, 1, 185]
    ],
    [
        [15, 0, 1, 185],
        [11, 0, 1, 185],
        [12, 0, 1, 185],
        [8, 0, 1, 185],
        [9, 0, 1, 185],
        [13, 0, 1, 185],
        [10, 0, 1, 185],
        [14, 0, 1, 185]
    ],
    [
        [17, -256, -128, 233],
        [18, -256, -128, 233],
        [23, -256, -128, 233],
        [20, -256, -128, 233],
        [22, -256, -128, 233],
        [21, -256, -128, 233],
        [16, -256, -128, 233],
        [19, -256, -128, 233]
    ],
    [
        [30, -383, -255, 233],
        [24, -383, -255, 233],
        [25, -383, -255, 233],
        [31, -383, -255, 233],
        [27, -383, -255, 233],
        [29, -383, -255, 233],
        [28, -383, -255, 233],
        [26, -383, -255, 233]
    ]
];
var REDS1 = function(x) {
    return ((x & 0xFF) - (x >> 8));
};
var REDS2 = function(x) {
    return ((x & 0xFFFF) + (x >> 16));
};
var IF = function(x, y, z) {
    return ((y ^ z) & x) ^ (z);
};
var MAJ = function(x, y, z) {
    return (x & y) | ((x | y) & (z));
};
var FFT_LOOP = function(q, qOffset, hk, as) {
    var u, v;
    var m = q[(qOffset)];
    var n = q[(qOffset) + (hk)];
    q[(qOffset)] = m + n;
    q[(qOffset) + (hk)] = m - n;
    u = v = 0;
    var firstTime = true;
    for (; u < (hk); u += 4, v += 4 * (as)) {
        if (!firstTime) {
            var t;
            m = q[(qOffset) + u + 0];
            n = q[(qOffset) + u + 0 + (hk)];
            t = REDS2(n * alpha_tab[v + 0 * (as)]);
            q[(qOffset) + u + 0] = m + t;
            q[(qOffset) + u + 0 + (hk)] = m - t;
        }
        else {
            firstTime = false;
        }
        m = q[(qOffset) + u + 1];
        n = q[(qOffset) + u + 1 + (hk)];
        t = REDS2(n * alpha_tab[v + Number(as)]);
        q[(qOffset) + u + 1] = m + t;
        q[(qOffset) + u + 1 + (hk)] = m - t;
        m = q[(qOffset) + u + 2];
        n = q[(qOffset) + u + 2 + (hk)];
        t = REDS2(n * alpha_tab[v + 2 * (as)]);
        q[(qOffset) + u + 2] = m + t;
        q[(qOffset) + u + 2 + (hk)] = m - t;
        m = q[(qOffset) + u + 3];
        n = q[(qOffset) + u + 3 + (hk)];
        t = REDS2(n * alpha_tab[v + 3 * (as)]);
        q[(qOffset) + u + 3] = m + t;
        q[(qOffset) + u + 3 + (hk)] = m - t;
    }
};
var FFT8 = function(x, xOffset, xs, d) {
    var x0 = x[(xOffset)];
    var x1 = x[(xOffset) + (xs)];
    var x2 = x[(xOffset) + 2 * (xs)];
    var x3 = x[(xOffset) + 3 * (xs)];
    var a0 = x0 + x2;
    var a1 = x0 + (x2 << 4);
    var a2 = x0 - x2;
    var a3 = x0 - (x2 << 4);
    var b0 = x1 + x3;
    var b1 = REDS1((x1 << 2) + (x3 << 6));
    var b2 = (x1 << 4) - (x3 << 4);
    var b3 = REDS1((x1 << 6) + (x3 << 2));
    d[0] = a0 + b0;
    d[1] = a1 + b1;
    d[2] = a2 + b2;
    d[3] = a3 + b3;
    d[4] = a0 - b0;
    d[5] = a1 - b1;
    d[6] = a2 - b2;
    d[7] = a3 - b3;
};
var FFT16 = function(x, xOffset, q, qOffset, xs) {
    var d1 = new Array(8);
    var d2 = new Array(8);
    FFT8(x, xOffset, (xs) << 1, d1);
    FFT8(x, (xOffset) + (xs), (xs) << 1, d2);
    for (var i = 0;i<8;i++) {
        q[(qOffset) + i] = d1[i] + (d2[i] << i);
    }
    for (var i = 0;i<8;i++) {
        q[(qOffset) + 8 + i] = d1[i] - (d2[i] << i);
    }
};
var FFT32 = function(x, xOffset, q, qOffset, xs) {
    var xd = xs << 1;
    FFT16(x, xOffset, q, qOffset, xd);
    FFT16(x, xOffset + xs, q, qOffset + 16, xd);
    FFT_LOOP(q, qOffset, 16, 8);
};
var FFT64 = function(x, xOffset, q, qOffset, xs) {
    var xd = xs << 1;
    FFT32(x, xOffset, q, qOffset, xd);
    FFT32(x, xOffset + xs, q, qOffset + 32, xd);
    FFT_LOOP(q, qOffset, 32, 4);
};
var FFT256 = function(x, xOffset, q, qOffset, xs) {
    FFT64(x, xOffset, q, qOffset, (xs) << 2);
    FFT64(x, (xOffset) + ((xs) * 2), q, qOffset + 64, (xs) << 2);
    FFT_LOOP(q, qOffset, 64, 2);
    FFT64(x, (xOffset) + (Number(xs)), q, qOffset + 128, (xs) << 2);
    FFT64(x, (xOffset) + ((xs) * 3), q, qOffset + 192, (xs) << 2);
    FFT_LOOP(q, qOffset + 128, 64, 2);
    FFT_LOOP(q, qOffset, 128, 1);
};
var PP8 = [
    [1, 0, 3, 2, 5, 4, 7, 6],
    [6, 7, 4, 5, 2, 3, 0, 1],
    [2, 3, 0, 1, 6, 7, 4, 5],
    [3, 2, 1, 0, 7, 6, 5, 4],
    [5, 4, 7, 6, 1, 0, 3, 2],
    [7, 6, 5, 4, 3, 2, 1, 0],
    [4, 5, 6, 7, 0, 1, 2, 3]
];
var M7 = [
    [0, 1, 2, 3],
    [1, 2, 3, 4],
    [2, 3, 4, 5],
    [3, 4, 5, 6],
    [4, 5, 6, 0],
    [5, 6, 0, 1],
    [6, 0, 1, 2],
    [0, 1, 2, 3]
];
var INNER = function(l, h, mm) {
    return (((l * mm) & 0xFFFF) + ((h * mm) << 16));
};
var W_BIG = function(sb, o1, o2, mm, q) {
    var r = new Array(8);
    for (var i = 0;i<8;i++) {
        r[i] = INNER(q[16 * (sb) + 2 * i + o1], q[16 * (sb) + 2 * i + o2], mm);
    }
    return r;
};
var WB = function(x, y, q) {
    var wb = WB_DATA[x][y];
    return W_BIG(wb[0], wb[1], wb[2], wb[3], q);
};
var STEP_ELT = function(n, w, fun, s, ppb, tA, A, B, C, D) {
    var tt = op.t32(D[n] + (w) + fun(A[n], B[n], C[n]));
    A[n] = op.t32(op.rotl32(tt, s) + tA[ppb[n]]);
    D[n] = C[n];
    C[n] = B[n];
    B[n] = tA[n];
};
var STEP_BIG = function(w, fun, r, s, pp8b, A, B, C, D) {
    var tA = new Array(8);
    for (var i = 0;i<8;i++) {
        tA[i] = op.rotl32(A[i], r);
    }
    for (var i = 0;i<8;i++) {
        STEP_ELT(i, w[i], fun, s, pp8b, tA, A, B, C, D);
    }
};
var ONE_ROUND_BIG = function(ri, isp, p0, p1, p2, p3, A, B, C, D, q) {
    STEP_BIG(WB(ri, 0, q), IF, p0, p1, PP8[M7[0][isp]], A, B, C, D);
    STEP_BIG(WB(ri, 1, q), IF, p1, p2, PP8[M7[1][isp]], A, B, C, D);
    STEP_BIG(WB(ri, 2, q), IF, p2, p3, PP8[M7[2][isp]], A, B, C, D);
    STEP_BIG(WB(ri, 3, q), IF, p3, p0, PP8[M7[3][isp]], A, B, C, D);
    STEP_BIG(WB(ri, 4, q), MAJ, p0, p1, PP8[M7[4][isp]], A, B, C, D);
    STEP_BIG(WB(ri, 5, q), MAJ, p1, p2, PP8[M7[5][isp]], A, B, C, D);
    STEP_BIG(WB(ri, 6, q), MAJ, p2, p3, PP8[M7[6][isp]], A, B, C, D);
    STEP_BIG(WB(ri, 7, q), MAJ, p3, p0, PP8[M7[7][isp]], A, B, C, D);
};
var compress = function(ctx, last) {
    var q = new Array(256);
    var i;
    var A = new Array(8);
    var B = new Array(8);
    var C = new Array(8);
    var D = new Array(8);
    FFT256(ctx.buffer, 0, q, 0, 1);
    if (last) {
        for (i = 0; i < 256; i++) {
            var tq;
            tq = q[i] + yoff_b_f[i];
            tq = REDS2(tq);
            tq = REDS1(tq);
            tq = REDS1(tq);
            q[i] = (tq <= 128 ? tq : tq - 257);
        }
    }
    else {
        for (i = 0; i < 256; i++) {
            var tq;
            tq = q[i] + yoff_b_n[i];
            tq = REDS2(tq);
            tq = REDS1(tq);
            tq = REDS1(tq);
            q[i] = (tq <= 128 ? tq : tq - 257);
        }
    }
    op.bufferInsert(A,0,ctx.state,8);
    op.bufferInsert(B,0,ctx.state,8,8);
    op.bufferInsert(C,0,ctx.state,8,16);
    op.bufferInsert(D,0,ctx.state,8,24);
    var x = op.swap32Array(h.bytes2Int32Buffer(ctx.buffer));
    op.bufferXORInsert(A,0,x,0,8);
    op.bufferXORInsert(B,0,x,8,8);
    op.bufferXORInsert(C,0,x,16,8);
    op.bufferXORInsert(D,0,x,24,8);
    ONE_ROUND_BIG(0, 0, 3, 23, 17, 27, A, B, C, D, q);
    ONE_ROUND_BIG(1, 1, 28, 19, 22, 7, A, B, C, D, q);
    ONE_ROUND_BIG(2, 2, 29, 9, 15, 5, A, B, C, D, q);
    ONE_ROUND_BIG(3, 3, 4, 13, 10, 25, A, B, C, D, q);
    STEP_BIG(ctx.state.slice(0, 8),IF, 4, 13, PP8[4],A,B,C,D);
    STEP_BIG(ctx.state.slice(8, 16),IF, 13, 10, PP8[5],A,B,C,D);
    STEP_BIG(ctx.state.slice(16, 24),IF, 10, 25, PP8[6],A,B,C,D);
    STEP_BIG(ctx.state.slice(24, 32),IF, 25, 4, PP8[0],A,B,C,D);
    op.bufferInsert(ctx.state,0,A,8);
    op.bufferInsert(ctx.state,8,B,8);
    op.bufferInsert(ctx.state,16,C,8);
    op.bufferInsert(ctx.state,24,D,8);
};
var simd = function(ctx, data) {
    var len = data.length;
    while (len > 0) {
        var clen = ctx.buffer.length - ctx.ptr;
        if (clen > len) clen = len;
        op.bufferInsert(ctx.buffer, ctx.ptr, data, clen);
        ctx.ptr += clen;
        data = data.slice(clen);
        len -= clen;
        if (ctx.ptr === ctx.buffer.length) {
            compress(ctx, 0);
            ctx.ptr = 0;
            ctx.countLow = op.t32(ctx.countLow + 1);
            if (ctx.countLow === 0) ctx.countHigh++;
        }
    }
};
var encode_count = function(dst, offset, low, high, ptr, n) {
    low = op.t32(low << 10);
    high = op.t32(high << 10) + (low >> 22);
    low += (ptr << 3) + n;
    dst[offset] = low & 0xFF;
    dst[offset + 1] = (low & 0xFF00) >>> 8;
    dst[offset + 2] = (low & 0xFF0000) >>> 8;
    dst[offset + 3] = (low & 0xFF000000) >>> 8;
    dst[offset + 4] = high & 0xFF;
    dst[offset + 5] = (high & 0xFF00) >>> 8;
    dst[offset + 6] = (high & 0xFF0000) >>> 8;
    dst[offset + 7] = (high & 0xFF000000) >>> 8;
};
var simdClose = function(ctx, ub, n) {
    var buf = ctx.buffer;
    var ptr = ctx.ptr;
    var d;
    var u;
    if (ctx.ptr > 0 || n > 0) {
        op.bufferSet(buf, ptr, 0, buf.length - ptr);
        buf[ptr] = ub & (0xFF << (8 - n));
        compress(ctx, 0);
    }
    op.bufferSet(buf, 0, 0, buf.length);
    encode_count(buf, 0, ctx.countLow, ctx.countHigh, ctx.ptr, n);
    compress(ctx, 1);
    var out = new Array(16);
    for (u = 0; u < 16; u++) out[u] = op.swap32(ctx.state[u]);
    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 = IV512.slice();
    ctx.ptr = 0;
    ctx.countLow = 0;
    ctx.countHigh = 0;
    ctx.buffer = new Array(128);
    simd(ctx, msg);
    var r = simdClose(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;
};