UNPKG

c11-hash-js

Version:

c11 javascript hashing algorithm in pure javascript

485 lines (462 loc) 11.5 kB
///////////////////////////////////// ////////////// Luffa /////////////// //// Written by Quantum Explorer //// ////////// Dash Foundation ////////// /// Released under the MIT License // ///////////////////////////////////// var o = require('./op'); var h = require('./helper'); var V_INIT = [ [ 0x6d251e69, 0x44b051e0, 0x4eaa6fb4, 0xdbf78465, 0x6e292011, 0x90152df4, 0xee058139, 0xdef610bb ], [ 0xc3b44b95, 0xd9d2f256, 0x70eee9a0, 0xde099fa3, 0x5d9b0557, 0x8fc944b3, 0xcf1ccf0e, 0x746cd581 ], [ 0xf7efc89d, 0x5dba5781, 0x04016ce5, 0xad659c05, 0x0306194f, 0x666d1836, 0x24aa230a, 0x8b264ae7 ], [ 0x858075d5, 0x36d79cce, 0xe571f7d7, 0x204b1f67, 0x35870c6a, 0x57e9e923, 0x14bcb808, 0x7cde72ce ], [ 0x6c68e9be, 0x5ec41e22, 0xc825b7c7, 0xaffb4363, 0xf5df3999, 0x0fc688f1, 0xb07224cc, 0x03e86cea ] ]; var RC00 = [ 0x303994a6, 0xc0e65299, 0x6cc33a12, 0xdc56983e, 0x1e00108f, 0x7800423d, 0x8f5b7882, 0x96e1db12 ]; var RC04 = [ 0xe0337818, 0x441ba90d, 0x7f34d442, 0x9389217f, 0xe5a8bce6, 0x5274baf4, 0x26889ba7, 0x9a226e9d ]; var RC10 = [ 0xb6de10ed, 0x70f47aae, 0x0707a3d4, 0x1c1e8f51, 0x707a3d45, 0xaeb28562, 0xbaca1589, 0x40a46f3e ]; var RC14 = [ 0x01685f3d, 0x05a17cf4, 0xbd09caca, 0xf4272b28, 0x144ae5cc, 0xfaa7ae2b, 0x2e48f1c1, 0xb923c704 ]; var RC20 = [ 0xfc20d9d2, 0x34552e25, 0x7ad8818f, 0x8438764a, 0xbb6de032, 0xedb780c8, 0xd9847356, 0xa2c78434 ]; var RC24 = [ 0xe25e72c1, 0xe623bb72, 0x5c58a4a4, 0x1e38e2e7, 0x78e38b9d, 0x27586719, 0x36eda57f, 0x703aace7 ]; var RC30 = [ 0xb213afa5, 0xc84ebe95, 0x4e608a22, 0x56d858fe, 0x343b138f, 0xd0ec4e3d, 0x2ceb4882, 0xb3ad2208 ]; var RC34 = [ 0xe028c9bf, 0x44756f91, 0x7e8fce32, 0x956548be, 0xfe191be2, 0x3cb226e5, 0x5944a28e, 0xa1c4c355 ]; var RC40 = [ 0xf0d2e9e3, 0xac11d7fa, 0x1bcb66f2, 0x6f2d9bc9, 0x78602649, 0x8edae952, 0x3b6ba548, 0xedae9520 ]; var RC44 = [ 0x5090d577, 0x2d1925ab, 0xb46496ac, 0xd1925ab0, 0x29131ab6, 0x0fc053c3, 0x3f014f0c, 0xfc053c31 ]; var M2 = function(d, s) { var tmp = s[7]; d[7] = s[6]; d[6] = s[5]; d[5] = s[4]; d[4] = s[3] ^ tmp; d[3] = s[2] ^ tmp; d[2] = s[1]; d[1] = s[0] ^ tmp; d[0] = tmp; } //V is a table of states var MI5 = function(buf, V) { var M = Array(8); var a = Array(8); var b = Array(8); M[0] = buf[0]; M[1] = buf[1]; M[2] = buf[2]; M[3] = buf[3]; M[4] = buf[4]; M[5] = buf[5]; M[6] = buf[6]; M[7] = buf[7]; o.xORTable(a, V[0], V[1], 8); o.xORTable(b, V[2], V[3], 8); o.xORTable(a, a, b, 8); o.xORTable(a, a, V[4], 8); M2(a, a); o.xORTable(V[0], a, V[0], 8); o.xORTable(V[1], a, V[1], 8); o.xORTable(V[2], a, V[2], 8); o.xORTable(V[3], a, V[3], 8); o.xORTable(V[4], a, V[4], 8); M2(b, V[0]); o.xORTable(b, b, V[1], 8); M2(V[1], V[1]); o.xORTable(V[1], V[1], V[2], 8); M2(V[2], V[2]); o.xORTable(V[2], V[2], V[3], 8); M2(V[3], V[3]); o.xORTable(V[3], V[3], V[4], 8); M2(V[4], V[4]); o.xORTable(V[4], V[4], V[0], 8); M2(V[0], b); o.xORTable(V[0], V[0], V[4], 8); M2(V[4], V[4]); o.xORTable(V[4], V[4], V[3], 8); M2(V[3], V[3]); o.xORTable(V[3], V[3], V[2], 8); M2(V[2], V[2]); o.xORTable(V[2], V[2], V[1], 8); M2(V[1], V[1]); o.xORTable(V[1], V[1], b, 8); o.xORTable(V[0], V[0], M, 8); M2(M, M); o.xORTable(V[1], V[1], M, 8); M2(M, M); o.xORTable(V[2], V[2], M, 8); M2(M, M); o.xORTable(V[3], V[3], M, 8); M2(M, M); o.xORTable(V[4], V[4], M, 8); } var TWEAK5 = function(V) { V[1][4] = o.rotl32(V[1][4], 1); V[1][5] = o.rotl32(V[1][5], 1); V[1][6] = o.rotl32(V[1][6], 1); V[1][7] = o.rotl32(V[1][7], 1); V[2][4] = o.rotl32(V[2][4], 2); V[2][5] = o.rotl32(V[2][5], 2); V[2][6] = o.rotl32(V[2][6], 2); V[2][7] = o.rotl32(V[2][7], 2); V[3][4] = o.rotl32(V[3][4], 3); V[3][5] = o.rotl32(V[3][5], 3); V[3][6] = o.rotl32(V[3][6], 3); V[3][7] = o.rotl32(V[3][7], 3); V[4][4] = o.rotl32(V[4][4], 4); V[4][5] = o.rotl32(V[4][5], 4); V[4][6] = o.rotl32(V[4][6], 4); V[4][7] = o.rotl32(V[4][7], 4); } var SUB_CRUMB = function(a0, a1, a2, a3) { var tmp; tmp = (a0); (a0) |= (a1); (a2) ^= (a3); (a1) = o.t32(~(a1)); (a0) ^= (a3); (a3) &= tmp; (a1) ^= (a3); (a3) ^= (a2); (a2) &= (a0); (a0) = o.t32(~(a0)); (a2) ^= (a1); (a1) |= (a3); tmp ^= (a1); (a3) ^= (a2); (a2) &= (a1); (a1) ^= (a0); (a0) = tmp; return [a0, a1, a2, a3]; } var MIX_WORD = function(u, v) { (v) ^= (u); (u) = o.rotl32((u), 2) ^ (v); (v) = o.rotl32((v), 14) ^ (u); (u) = o.rotl32((u), 10) ^ (v); (v) = o.rotl32((v), 1); return [u,v]; } var P5 = function(V) { TWEAK5(V); var tmp; for (var r = 0; r < 8; r++) { tmp = SUB_CRUMB(V[0][0], V[0][1], V[0][2], V[0][3]); V[0][0] = tmp[0]; V[0][1] = tmp[1]; V[0][2] = tmp[2]; V[0][3] = tmp[3]; tmp = SUB_CRUMB(V[0][5], V[0][6], V[0][7], V[0][4]); V[0][5] = tmp[0]; V[0][6] = tmp[1]; V[0][7] = tmp[2]; V[0][4] = tmp[3]; tmp = MIX_WORD(V[0][0], V[0][4]); V[0][0] = tmp[0]; V[0][4] = tmp[1]; tmp = MIX_WORD(V[0][1], V[0][5]); V[0][1] = tmp[0]; V[0][5] = tmp[1]; tmp = MIX_WORD(V[0][2], V[0][6]); V[0][2] = tmp[0]; V[0][6] = tmp[1]; tmp = MIX_WORD(V[0][3], V[0][7]); V[0][3] = tmp[0]; V[0][7] = tmp[1]; V[0][0] ^= RC00[r]; V[0][4] ^= RC04[r]; } for (var r = 0; r < 8; r++) { tmp = SUB_CRUMB(V[1][0], V[1][1], V[1][2], V[1][3]); V[1][0] = tmp[0]; V[1][1] = tmp[1]; V[1][2] = tmp[2]; V[1][3] = tmp[3]; tmp = SUB_CRUMB(V[1][5], V[1][6], V[1][7], V[1][4]); V[1][5] = tmp[0]; V[1][6] = tmp[1]; V[1][7] = tmp[2]; V[1][4] = tmp[3]; tmp = MIX_WORD(V[1][0], V[1][4]); V[1][0] = tmp[0]; V[1][4] = tmp[1]; tmp = MIX_WORD(V[1][1], V[1][5]); V[1][1] = tmp[0]; V[1][5] = tmp[1]; tmp = MIX_WORD(V[1][2], V[1][6]); V[1][2] = tmp[0]; V[1][6] = tmp[1]; tmp = MIX_WORD(V[1][3], V[1][7]); V[1][3] = tmp[0]; V[1][7] = tmp[1]; V[1][0] ^= RC10[r]; V[1][4] ^= RC14[r]; } for (var r = 0; r < 8; r++) { tmp = SUB_CRUMB(V[2][0], V[2][1], V[2][2], V[2][3]); V[2][0] = tmp[0]; V[2][1] = tmp[1]; V[2][2] = tmp[2]; V[2][3] = tmp[3]; tmp = SUB_CRUMB(V[2][5], V[2][6], V[2][7], V[2][4]); V[2][5] = tmp[0]; V[2][6] = tmp[1]; V[2][7] = tmp[2]; V[2][4] = tmp[3]; tmp = MIX_WORD(V[2][0], V[2][4]); V[2][0] = tmp[0]; V[2][4] = tmp[1]; tmp = MIX_WORD(V[2][1], V[2][5]); V[2][1] = tmp[0]; V[2][5] = tmp[1]; tmp = MIX_WORD(V[2][2], V[2][6]); V[2][2] = tmp[0]; V[2][6] = tmp[1]; tmp = MIX_WORD(V[2][3], V[2][7]); V[2][3] = tmp[0]; V[2][7] = tmp[1]; V[2][0] ^= RC20[r]; V[2][4] ^= RC24[r]; } for (var r = 0; r < 8; r++) { tmp = SUB_CRUMB(V[3][0], V[3][1], V[3][2], V[3][3]); V[3][0] = tmp[0]; V[3][1] = tmp[1]; V[3][2] = tmp[2]; V[3][3] = tmp[3]; tmp = SUB_CRUMB(V[3][5], V[3][6], V[3][7], V[3][4]); V[3][5] = tmp[0]; V[3][6] = tmp[1]; V[3][7] = tmp[2]; V[3][4] = tmp[3]; tmp = MIX_WORD(V[3][0], V[3][4]); V[3][0] = tmp[0]; V[3][4] = tmp[1]; tmp = MIX_WORD(V[3][1], V[3][5]); V[3][1] = tmp[0]; V[3][5] = tmp[1]; tmp = MIX_WORD(V[3][2], V[3][6]); V[3][2] = tmp[0]; V[3][6] = tmp[1]; tmp = MIX_WORD(V[3][3], V[3][7]); V[3][3] = tmp[0]; V[3][7] = tmp[1]; V[3][0] ^= RC30[r]; V[3][4] ^= RC34[r]; } for (var r = 0; r < 8; r++) { tmp = SUB_CRUMB(V[4][0], V[4][1], V[4][2], V[4][3]); V[4][0] = tmp[0]; V[4][1] = tmp[1]; V[4][2] = tmp[2]; V[4][3] = tmp[3]; tmp = SUB_CRUMB(V[4][5], V[4][6], V[4][7], V[4][4]); V[4][5] = tmp[0]; V[4][6] = tmp[1]; V[4][7] = tmp[2]; V[4][4] = tmp[3]; tmp = MIX_WORD(V[4][0], V[4][4]); V[4][0] = tmp[0]; V[4][4] = tmp[1]; tmp = MIX_WORD(V[4][1], V[4][5]); V[4][1] = tmp[0]; V[4][5] = tmp[1]; tmp = MIX_WORD(V[4][2], V[4][6]); V[4][2] = tmp[0]; V[4][6] = tmp[1]; tmp = MIX_WORD(V[4][3], V[4][7]); V[4][3] = tmp[0]; V[4][7] = tmp[1]; V[4][0] ^= RC40[r]; V[4][4] ^= RC44[r]; } } var luffa5 = function(ctx, data) { var buf, ptr; //create a local copy of states var V = new Array(5); for (var i = 0; i < 5; i++) { V[i] = new Array(8); } buf = ctx.buffer; ptr = ctx.ptr; var len = data.length; if (len < ctx.buffer.length - ptr) { o.bufferInsert(buf, ptr, data, data.length); ptr += data.length; ctx.ptr = ptr; return; } //perform a deep copy of current state for (var i = 0; i < 5; i++) { for (var j = 0; j < 8; j++) { V[i][j] = ctx.state[i][j]; } } while (len > 0) { var clen = ctx.buffer.length - ptr; if (clen > len) clen = len; o.bufferInsert(buf, ptr, data, clen); ptr += clen; data = data.slice(clen); len -= clen; if (ptr === ctx.buffer.length) { var int32Buf = h.bytes2Int32Buffer(buf); MI5(int32Buf, V); P5(V); ptr = 0; } } ctx.state = V; ctx.ptr = ptr; } var luffa5Close = function(ctx, ub, n) { var buf, out, ptr, z, i; var V = new Array(5); for (var i = 0; i < 5; i++) { V[i] = new Array(8); } buf = ctx.buffer; ptr = ctx.ptr; z = 0x80 >> n; buf[ptr++] = ((ub & -z) | z) & 0xFF; o.bufferSet(buf, ptr, 0, ctx.buffer.length - ptr); for (var i = 0; i < 5; i++) { for (var j = 0; j < 8; j++) { V[i][j] = ctx.state[i][j]; } } var out = new Array(16); for (i = 0; i < 3; i++) { var int32Buf = h.bytes2Int32Buffer(buf); MI5(int32Buf, V); P5(V); switch (i) { case 0: o.bufferSet(buf, 0, 0, ctx.buffer.length); break; case 1: out[0] = V[0][0] ^ V[1][0] ^ V[2][0] ^ V[3][0] ^ V[4][0]; out[1] = V[0][1] ^ V[1][1] ^ V[2][1] ^ V[3][1] ^ V[4][1]; out[2] = V[0][2] ^ V[1][2] ^ V[2][2] ^ V[3][2] ^ V[4][2]; out[3] = V[0][3] ^ V[1][3] ^ V[2][3] ^ V[3][3] ^ V[4][3]; out[4] = V[0][4] ^ V[1][4] ^ V[2][4] ^ V[3][4] ^ V[4][4]; out[5] = V[0][5] ^ V[1][5] ^ V[2][5] ^ V[3][5] ^ V[4][5]; out[6] = V[0][6] ^ V[1][6] ^ V[2][6] ^ V[3][6] ^ V[4][6]; out[7] = V[0][7] ^ V[1][7] ^ V[2][7] ^ V[3][7] ^ V[4][7]; break; case 2: out[8] = V[0][0] ^ V[1][0] ^ V[2][0] ^ V[3][0] ^ V[4][0]; out[9] = V[0][1] ^ V[1][1] ^ V[2][1] ^ V[3][1] ^ V[4][1]; out[10] = V[0][2] ^ V[1][2] ^ V[2][2] ^ V[3][2] ^ V[4][2]; out[11] = V[0][3] ^ V[1][3] ^ V[2][3] ^ V[3][3] ^ V[4][3]; out[12] = V[0][4] ^ V[1][4] ^ V[2][4] ^ V[3][4] ^ V[4][4]; out[13] = V[0][5] ^ V[1][5] ^ V[2][5] ^ V[3][5] ^ V[4][5]; out[14] = V[0][6] ^ V[1][6] ^ V[2][6] ^ V[3][6] ^ V[4][6]; out[15] = V[0][7] ^ V[1][7] ^ V[2][7] ^ V[3][7] ^ V[4][7]; break; } } 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 = V_INIT; ctx.ptr = 0; ctx.buffer = new Array(32); luffa5(ctx, msg); var r = luffa5Close(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; }