c11-hash-js
Version:
c11 javascript hashing algorithm in pure javascript
219 lines (206 loc) • 6.32 kB
JavaScript
/////////////////////////////////////
/////////////// Blake //////////////
//// Written by Quantum Explorer ////
////////// Dash Foundation //////////
/// Released under the MIT License //
/////////////////////////////////////
var o = require('./op');
var h = require('./helper');
var CB = h.bytes2Int64Buffer(h.b64Decode("JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxObIlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjftawv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXTmk="));
// var CB = [
// o.u(0x243f6a88, 0x85a308d3),
// o.u(0x13198a2e, 0x03707344),
// o.u(0xa4093822, 0x299f31d0),
// o.u(0x082efa98, 0xec4e6c89),
// o.u(0x452821e6, 0x38d01377),
// o.u(0xbe5466cf, 0x34e90c6c),
// o.u(0xc0ac29b7, 0xc97c50dd),
// o.u(0x3f84d5b5, 0xb5470917),
// o.u(0x9216d5d9, 0x8979fb1b),
// o.u(0xd1310ba6, 0x98dfb5ac),
// o.u(0x2ffd72db, 0xd01adfb7),
// o.u(0xb8e1afed, 0x6a267e96),
// o.u(0xba7c9045, 0xf12c7f99),
// o.u(0x24a19947, 0xb3916cf7),
// o.u(0x0801f2e2, 0x858efc16),
// o.u(0x636920d8, 0x71574e69)
// ];
var Z = [
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
[14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3],
[11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4],
[7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8],
[9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13],
[2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9],
[12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11],
[13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10],
[6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5],
[10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0]
];
var initialValues = [
o.u(0x6a09e667, 0xf3bcc908),
o.u(0xbb67ae85, 0x84caa73b),
o.u(0x3c6ef372, 0xfe94f82b),
o.u(0xa54ff53a, 0x5f1d36f1),
o.u(0x510e527f, 0xade682d1),
o.u(0x9b05688c, 0x2b3e6c1f),
o.u(0x1f83d9ab, 0xfb41bd6b),
o.u(0x5be0cd19, 0x137e2179)
];
var GB = function(m0, m1, c0, c1, a, b, c, d) {
a.add(m0.xor(c1).add(b));
d.setxorOne(a).setFlip();
c.add(d);
b.setxorOne(c).setRotateRight(25);
a.add(m1.xor(c0).add(b));
d.setxorOne(a).setRotateRight(16);
c.add(d);
b.setxorOne(c).setRotateRight(11);
}
var round = function(r, V, M) {
GB(M[Z[r][0]], M[Z[r][1]], CB[Z[r][0]], CB[Z[r][1]], V[0], V[4], V[8], V[0xC]);
GB(M[Z[r][2]], M[Z[r][3]], CB[Z[r][2]], CB[Z[r][3]], V[1], V[5], V[9], V[0xD]);
GB(M[Z[r][4]], M[Z[r][5]], CB[Z[r][4]], CB[Z[r][5]], V[2], V[6], V[0xA], V[0xE]);
GB(M[Z[r][6]], M[Z[r][7]], CB[Z[r][6]], CB[Z[r][7]], V[3], V[7], V[0xB], V[0xF]);
GB(M[Z[r][8]], M[Z[r][9]], CB[Z[r][8]], CB[Z[r][9]], V[0], V[5], V[0xA], V[0xF]);
GB(M[Z[r][10]], M[Z[r][11]], CB[Z[r][10]], CB[Z[r][11]], V[1], V[6], V[0xB], V[0xC]);
GB(M[Z[r][12]], M[Z[r][13]], CB[Z[r][12]], CB[Z[r][13]], V[2], V[7], V[8], V[0xD]);
GB(M[Z[r][14]], M[Z[r][15]], CB[Z[r][14]], CB[Z[r][15]], V[3], V[4], V[9], V[0xE]);
}
var compress = function(M, H, S, T0, T1) {
var V = new Array(16);
o.bufferInsert64(V, 0, H, 8);
V[8] = S[0].xor(CB[0]);
V[9] = S[1].xor(CB[1]);
V[10] = S[2].xor(CB[2]);
V[11] = S[3].xor(CB[3]);
V[12] = T0.xor(CB[4]);
V[13] = T0.xor(CB[5]);
V[14] = T1.xor(CB[6]);
V[15] = T1.xor(CB[7]);
for (var i = 0; i < 16; i++) {
round(i % 10, V, M);
}
for (var i = 0; i < 8; i++) {
H[i] = o.xor64(H[i], S[i % 4], V[i], V[8 + i]);
}
}
var blake = function(ctx, data, len) {
var buf, ptr;
//create a local copy of states
var H = new Array(8);
var S = new Array(4);
var T0 = ctx.T0.clone();
var T1 = ctx.T1.clone();
buf = ctx.buffer;
ptr = ctx.ptr;
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
o.bufferInsert(H, 0, ctx.state, 8);
o.bufferInsert(S, 0, ctx.salt, 4);
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) {
T0.add(o.u(0, 1024));
if (T0.hi < 0 || T0.lo < 1024)
T1.addOne();
var int64Buf = h.bytes2Int64Buffer(buf);
compress(int64Buf, H, S, T0, T1);
ptr = 0;
}
}
ctx.state = H;
ctx.salt = S;
ctx.T0 = T0;
ctx.T1 = T1;
ctx.ptr = ptr;
}
var blakeClose = function(ctx) {
var buf = new Array(128);
var ptr = ctx.ptr;
var bitLen = (o.u(0, ptr)).shiftLeft(3);
var len = buf.length;
var padLen;
var count;
var tl = ctx.T0.plus(bitLen);
var th = ctx.T1.clone();
buf[ptr] = 0x80;
if (ptr === 0) {
ctx.T0 = o.u(0xFFFFFFFF, 0xFFFFFC00);
ctx.T1 = o.u(0xFFFFFFFF, 0xFFFFFFFF);
}
else if (ctx.T0.isZero()) {
ctx.T0 = o.u(0xFFFFFFFF, 0xFFFFFC00).plus(bitLen);
ctx.T1 = ctx.T1.minus(o.u(0, 1));
}
else {
ctx.T0 = ctx.T0.minus(o.u(0, 1024).minus(bitLen));
}
if (bitLen.lo <= 894) {
o.bufferSet(buf, ptr + 1, 0, 111 - ptr);
buf[111] |= 1;
h.bufferEncode64(buf, 112, th);
h.bufferEncode64(buf, 120, tl);
blake(ctx, buf.slice(ptr), 128 - ptr);
}
else {
o.bufferSet(u.buf, ptr + 1, 0, 127 - ptr);
blake(ctx, buf.slice(ptr), 128 - ptr);
ctx.T0 = o.u(0xFFFFFFFF,0xFFFFFC00);
ctx.T1 = o.u(0xFFFFFFFF,0xFFFFFFFF);
o.bufferSet(buf, 0, 0, 112);
buf[111] = 1;
h.bufferEncode64(buf, 112, th);
h.bufferEncode64(buf, 120, tl);
blake(ctx, buf, 128);
}
var out = new Array(16);
for (var u = 0; u < 8; u++) {
out[2 * u] = ctx.state[u].hi;
out[2 * u + 1] = ctx.state[u].lo;
}
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(initialValues);
var zero = o.u(0,0);
ctx.salt = [zero, zero, zero, zero];
ctx.T0 = zero.clone();
ctx.T1 = zero.clone();
ctx.ptr = 0;
ctx.buffer = new Array(128);
blake(ctx, msg, msg.length);
var r = blakeClose(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;
}