UNPKG

@gohelpfund/x11-hash-js

Version:

x11 javascript hashing algorithm in pure javascript

285 lines (264 loc) 7.52 kB
'use strict'; ///////////////////////////////////// /////////////// Echo /////////////// //// Written by Quantum Explorer //// ////////// Dash Foundation ////////// /// Released under the MIT License // ///////////////////////////////////// var op = require('./op'); var h = require('./helper'); var aes = require('./aes'); var ECHO_BlockSize = 128; var subWords = function(W, pK) { for (var n = 0; n < 16; n++) { var X = W[n]; var Y = new Array(4); aes.AES_ROUND_LE(X, pK, Y); aes.AES_ROUND_NOKEY_LE(Y, X); if ((pK[0] = op.t32(pK[0] + 1)) === 0) { if ((pK[1] = op.t32(pK[1] + 1)) === 0) if ((pK[2] = op.t32(pK[2] + 1)) === 0) pK[3] = op.t32(pK[3] + 1); } } }; var shiftRow1 = function(W, a, b, c, d) { var tmp; tmp = W[a][0]; W[a][0] = W[b][0]; W[b][0] = W[c][0]; W[c][0] = W[d][0]; W[d][0] = tmp; tmp = W[a][1]; W[a][1] = W[b][1]; W[b][1] = W[c][1]; W[c][1] = W[d][1]; W[d][1] = tmp; tmp = W[a][2]; W[a][2] = W[b][2]; W[b][2] = W[c][2]; W[c][2] = W[d][2]; W[d][2] = tmp; tmp = W[a][3]; W[a][3] = W[b][3]; W[b][3] = W[c][3]; W[c][3] = W[d][3]; W[d][3] = tmp; }; var shiftRow2 = function(W, a, b, c, d) { var tmp; tmp = W[a][0]; W[a][0] = W[c][0]; W[c][0] = tmp; tmp = W[b][0]; W[b][0] = W[d][0]; W[d][0] = tmp; tmp = W[a][1]; W[a][1] = W[c][1]; W[c][1] = tmp; tmp = W[b][1]; W[b][1] = W[d][1]; W[d][1] = tmp; tmp = W[a][2]; W[a][2] = W[c][2]; W[c][2] = tmp; tmp = W[b][2]; W[b][2] = W[d][2]; W[d][2] = tmp; tmp = W[a][3]; W[a][3] = W[c][3]; W[c][3] = tmp; tmp = W[b][3]; W[b][3] = W[d][3]; W[d][3] = tmp; }; var shiftRow3 = function(W, a, b, c, d) { shiftRow1(W, d, c, b, a); }; var shiftRows = function(W) { shiftRow1(W, 1, 5, 9, 13); shiftRow2(W, 2, 6, 10, 14); shiftRow3(W, 3, 7, 11, 15); }; var mixColumn = function(W, ia, ib, ic, id) { for (var n = 0; n < 4; n++) { var a = W[ia][n]; var b = W[ib][n]; var c = W[ic][n]; var d = W[id][n]; var ab = a ^ b; var bc = b ^ c; var cd = c ^ d; var abx = ((ab & (0x80808080)) >>> 7) * 27 ^ ((ab & (0x7F7F7F7F)) << 1); var bcx = ((bc & (0x80808080)) >>> 7) * 27 ^ ((bc & (0x7F7F7F7F)) << 1); var cdx = ((cd & (0x80808080)) >>> 7) * 27 ^ ((cd & (0x7F7F7F7F)) << 1); W[ia][n] = abx ^ bc ^ d; W[ib][n] = bcx ^ a ^ cd; W[ic][n] = cdx ^ ab ^ d; W[id][n] = abx ^ bcx ^ cdx ^ ab ^ c; } }; var finalize = function(ctx, W) { var int32Buf = op.swap32Array(h.bytes2Int32Buffer(ctx.buffer)); for (var u = 0; u < 8; u++) { for (var v = 0; v < 4; v++) { ctx.state[u][v] ^= int32Buf[u * 4 + v] ^ W[u][v] ^ W[u + 8][v]; } } }; var inputBlock = function(ctx, W) { op.buffer2Insert(W, 0, 0, ctx.state, 8, 4); var int32Buf = op.swap32Array(h.bytes2Int32Buffer(ctx.buffer)); for (var u = 0; u < 8; u++) { W[u + 8][0] = (int32Buf[4 * u]); W[u + 8][1] = (int32Buf[4 * u + 1]); W[u + 8][2] = (int32Buf[4 * u + 2]); W[u + 8][3] = (int32Buf[4 * u + 3]); } }; var mixColumns = function(W) { mixColumn(W, 0, 1, 2, 3); mixColumn(W, 4, 5, 6, 7); mixColumn(W, 8, 9, 10, 11); mixColumn(W, 12, 13, 14, 15); }; var ROUND = function(W,K) { subWords(W,K); shiftRows(W); mixColumns(W); }; var compress = function(ctx) { var W = new Array(16); for (var i = 0; i < 16; i++) { W[i] = new Array(4); } var K = new Array(4); op.bufferInsert(K,0,ctx.C,4); inputBlock(ctx, W); for (var u = 0; u < 10; u++) { ROUND(W,K); } finalize(ctx,W); }; var incrCounter = function(ctx, val) { ctx.C[0] = op.t32(ctx.C[0] + op.t32(val)); if (ctx.C[0] < op.t32(val)) { if ((ctx.C[1] = op.t32(ctx.C[1] + 1)) === 0) { if ((ctx.C[2] = op.t32(ctx.C[2] + 1)) === 0) { ctx.C[3] = op.t32(ctx.C[3] + 1); } } } }; var echoInit = function(ctx) { ctx.state = new Array(8); for (var i = 0; i < 8; i++) { ctx.state[i] = new Array(4); } ctx.state[0][0] = 512; ctx.state[0][1] = ctx.state[0][2] = ctx.state[0][3] = 0; ctx.state[1][0] = 512; ctx.state[1][1] = ctx.state[1][2] = ctx.state[1][3] = 0; ctx.state[2][0] = 512; ctx.state[2][1] = ctx.state[2][2] = ctx.state[2][3] = 0; ctx.state[3][0] = 512; ctx.state[3][1] = ctx.state[3][2] = ctx.state[3][3] = 0; ctx.state[4][0] = 512; ctx.state[4][1] = ctx.state[4][2] = ctx.state[4][3] = 0; ctx.state[5][0] = 512; ctx.state[5][1] = ctx.state[5][2] = ctx.state[5][3] = 0; ctx.state[6][0] = 512; ctx.state[6][1] = ctx.state[6][2] = ctx.state[6][3] = 0; ctx.state[7][0] = 512; ctx.state[7][1] = ctx.state[7][2] = ctx.state[7][3] = 0; ctx.ptr = 0; ctx.C = new Array(4); op.bufferSet(ctx.C,0,0,4); ctx.buffer = new Array(ECHO_BlockSize); }; var echo = function(ctx, data) { var buf, ptr; buf = ctx.buffer; ptr = ctx.ptr; var len = data.length; if (len < ctx.buffer.length - ptr) { op.bufferInsert(buf, ptr, data, data.length); ptr += data.length; ctx.ptr = ptr; return; } while (len > 0) { var clen = ctx.buffer.length - ptr; if (clen > len) clen = len; op.bufferInsert(buf, ptr, data, clen); ptr += clen; data = data.slice(clen); len -= clen; if (ptr === ctx.buffer.length) { incrCounter(ctx, 1024); compress(ctx); ptr = 0; } } ctx.ptr = ptr; }; var echoClose = function(ctx) { var out = new Array(16); var buf = ctx.buffer; var len = ctx.buffer.length; var ptr = ctx.ptr; var elen = (ptr << 3); incrCounter(ctx, elen); var cBytes = h.int32Buffer2Bytes(op.swap32Array(ctx.C)); /* * If elen is zero, then this block actually contains no message * bit, only the first padding bit. */ if (elen === 0) { ctx.C[0] = ctx.C[1] = ctx.C[2] = ctx.C[3] = 0; } buf[ptr++] = 0x80; op.bufferSet(buf,ptr, 0, len - ptr); if (ptr > (len - 18)) { compress(ctx); op.bufferSet(ctx.C,0,0,4); op.bufferSet(buf, 0, 0,len); } buf[len - 17] = 2; op.bufferInsert(buf,len - 16, cBytes, 16); compress(ctx); for (var u = 0; u < 4; u++) { for (var v = 0; v < 4; v++) { out[u*4 + v] = op.swap32(ctx.state[u][v]); } } 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 = {}; echoInit(ctx); echo(ctx, msg); var r = echoClose(ctx); var out; if (output === 2) { out = r; } else if (output === 1) { out = h.int32Buffer2Bytes(r); } else { out = h.int32ArrayToHexString(r); } return out; };