Skip to content

Instantly share code, notes, and snippets.

@19h
Created February 20, 2013 21:10
Show Gist options
  • Save 19h/4999648 to your computer and use it in GitHub Desktop.
Save 19h/4999648 to your computer and use it in GitHub Desktop.
A compact V8-ECMAScript ("Javascript") implementation of the Scrypt-hashing algorithm.
var j = void 0,
k = require("crypto");
function m(a) {
for (var b = a.length, c = Array(b), f = 0; f < b; f++) c[f] = a.charCodeAt(f);
return c
}
var p, q, s;
function t() {
q = [1779033703, 3144134277, 1013904242, 2773480762, 1359893119, 2600822924, 528734635, 1541459225];
p = [];
s = 0
}
function A(a) {
p = "string" == typeof a ? p.concat(m(a)) : p.concat(a);
for (var b = 0; b + 64 <= p.length; b += 64) B(q, p.slice(b, b + 64));
p = p.slice(b);
s += a.length
}
function C() {
p[p.length] = 128;
if (56 < p.length) {
for (var a = p.length; 64 > a; a++) p[a] = 0;
B(q, p);
p.length = 0
}
for (a = p.length; 59 > a; a++) p[a] = 0;
p[59] = s >>> 29 & 255;
p[60] = s >>> 21 & 255;
p[61] = s >>> 13 & 255;
p[62] = s >>> 5 & 255;
p[63] = s << 3 & 255;
B(q, p);
for (var b = Array(32), a = 0; 8 > a; a++) b[4 * a + 0] = q[a] >>> 24, b[4 * a + 1] = q[a] >> 16 & 255, b[4 * a + 2] = q[a] >> 8 & 255, b[4 * a + 3] = q[a] & 255;
delete q;
delete p;
delete s;
return b
}
var D;
SHA256_hexchars = "0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f".split(",");
SHA256_K = [1116352408, 1899447441, 3049323471, 3921009573, 961987163, 1508970993, 2453635748, 2870763221, 3624381080, 310598401, 607225278, 1426881987, 1925078388, 2162078206, 2614888103, 3248222580, 3835390401, 4022224774, 264347078, 604807628, 770255983, 1249150122, 1555081692, 1996064986, 2554220882, 2821834349, 2952996808, 3210313671, 3336571891, 3584528711, 113926993, 338241895, 666307205, 773529912, 1294757372, 1396182291, 1695183700, 1986661051, 2177026350, 2456956037, 2730485921, 2820302411, 3259730800, 3345764771, 3516065817, 3600352804,
4094571909, 275423344, 430227734, 506948616, 659060556, 883997877, 958139571, 1322822218, 1537002063, 1747873779, 1955562222, 2024104815, 2227730452, 2361852424, 2428436474, 2756734187, 3204031479, 3329325298];
function B(a, b) {
for (var c = Array(16), f = 0; 16 > f; f++) c[f] = b[4 * f + 0] << 24 | b[4 * f + 1] << 16 | b[4 * f + 2] << 8 | b[4 * f + 3];
for (f = 16; 64 > f; f++) c[f] = ((c[f - 2] >>> 17 | c[f - 2] << 15) ^ (c[f - 2] >>> 19 | c[f - 2] << 13) ^ c[f - 2] >>> 10) + c[f - 7] + ((c[f - 15] >>> 7 | c[f - 15] << 25) ^ (c[f - 15] >>> 18 | c[f - 15] << 14) ^ c[f - 15] >>> 3) + c[f - 16] & 4294967295;
for (var d = [].concat(a), f = 0; 64 > f; f++) {
var i = d[7] + ((d[4] >>> 6 | d[4] << 26) ^ (d[4] >>> 11 | d[4] << 21) ^ (d[4] >>> 25 | d[4] << 7)) + (d[6] ^ d[4] & (d[5] ^ d[6])) + SHA256_K[f] + c[f],
h = ((d[0] >>> 2 | d[0] << 30) ^ (d[0] >>> 13 | d[0] << 19) ^ (d[0] >>> 22 | d[0] << 10)) + (d[0] & d[1] ^ d[2] & (d[0] ^ d[1]));
d.pop();
d.unshift(i + h & 4294967295);
d[4] = d[4] + i & 4294967295
}
for (f = 0; 8 > f; f++) a[f] = a[f] + d[f] & 4294967295
}
sha256 = {
n: function (a) {
D = "string" == typeof a ? m(a) : [].concat(a);
64 < D.length && (t(), A(D), D = C());
for (a = D.length; 64 > a; a++) D[a] = 0;
for (a = 0; 64 > a; a++) D[a] ^= 54;
t();
A(D)
},
update: function (a) {
A(a)
},
c: function () {
for (var a = C(), b = 0; 64 > b; b++) D[b] ^= 106;
t();
A(D);
A(a);
for (b = 0; 64 > b; b++) D[b] = 0;
delete D;
return C()
}
};
function E(a, b, c, f, d) {
for (; d--;) c[f++] = a[b++]
}
PBKDF = function (a, b, c, f) {
if (f > 32 * (Math.pow(2, 32) - 1)) throw Error("Requested key length too long");
var d = [],
i = [],
h = [],
e = Math.ceil(f / 32),
f = f - 32 * (e - 1);
E(b, 0, h, 0, b.length);
for (var g = 1; g <= e; g++) {
h[b.length + 0] = g >> 24 & 255;
h[b.length + 1] = g >> 16 & 255;
h[b.length + 2] = g >> 8 & 255;
h[b.length + 3] = g >> 0 & 255;
sha256.n(a);
sha256.update(h);
d = sha256.c();
E(d, 0, i, 0, 32);
for (var r = 1; 1 > r; r++) {
sha256.update(d);
for (var d = sha256.c(), l = 0; 32 > l; l++) i[l] ^= d[l]
}
E(i, 0, c, 32 * (g - 1), g == e ? f : 32)
}
};
function F() {
this.toString = function () {
return "BUG: " + this.message
};
this.message = "random: addEntropy only supports number, array or string"
}
function G(a, b) {
if (0 === a.length || 0 === b.length) return a.concat(b);
var c = a[a.length - 1],
f = H(c),
d;
if (32 === f) d = a.concat(b);
else {
d = b;
var c = c | 0,
i = a.slice(0, a.length - 1),
h;
for (i === j && (i = []); 32 <= f; f -= 32) i.push(c), c = 0;
if (0 === f) d = i.concat(d);
else {
for (h = 0; h < d.length; h++) i.push(c | d[h] >>> f), c = d[h] << 32 - f;
h = d.length ? d[d.length - 1] : 0;
d = H(h);
i.push(I(f + d & 31, 32 < f + d ? c : i.pop(), 1));
d = i
}
}
return d
}
function I(a, b, c) {
return 32 === a ? b : (c ? b | 0 : b << 32 - a) + 1099511627776 * a
}
function H(a) {
return Math.round(a / 1099511627776) || 32
}
function J(a) {
this.e[0] || this.q();
a ? (this.d = a.d.slice(0), this.b = a.b.slice(0), this.a = a.a) : this.reset()
}
J.hash = function (a) {
return (new J).update(a).c()
};
J.prototype = {
reset: function () {
this.d = this.i.slice(0);
this.b = [];
this.a = 0;
return this
},
update: function (a) {
if ("string" === typeof a) {
var a = unescape(encodeURIComponent(a)),
b = [],
c, f = 0;
for (c = 0; c < a.length; c++) f = f << 8 | a.charCodeAt(c), 3 === (c & 3) && (b.push(f), f = 0);
c & 3 && b.push(I(8 * (c & 3), f));
a = b
}
c = this.b = G(this.b, a);
b = this.a;
f = a.length;
a = this.a = b + (0 === f ? 0 : 32 * (f - 1) + H(a[f - 1]));
for (b = 512 + b & -512; b <= a; b += 512) this.h(c.splice(0, 16));
return this
},
c: function () {
var a, b = this.b,
c = this.d,
b = G(b, [I(1, 1)]);
for (a = b.length + 2; a & 15; a++) b.push(0);
b.push(Math.floor(this.a / 4294967296));
for (b.push(this.a | 0); b.length;) this.h(b.splice(0, 16));
this.reset();
return c
},
i: [],
e: [],
q: function () {
var a = 0,
b = 2,
c;
a: for (; 64 > a; b++) {
for (c = 2; c * c <= b; c++) if (0 === b % c) continue a;
8 > a && (this.i[a] = 4294967296 * (Math.pow(b, 0.5) - Math.floor(Math.pow(b, 0.5))) | 0);
this.e[a] = 4294967296 * (Math.pow(b, 1 / 3) - Math.floor(Math.pow(b, 1 / 3))) | 0;
a++
}
},
h: function (a) {
for (var b, c, f = a.slice(0), d = this.d, i = this.e, h = d[0], e = d[1], g = d[2], r = d[3], l = d[4], w = d[5], n = d[6], x = d[7], a = 0; 64 > a; a++) 16 > a ? b = f[a] : (b = f[a + 1 & 15], c = f[a + 14 & 15], b = f[a & 15] = (b >>> 7 ^ b >>> 18 ^ b >>> 3 ^ b << 25 ^ b << 14) + (c >>> 17 ^ c >>> 19 ^ c >>> 10 ^ c << 15 ^ c << 13) + f[a & 15] + f[a + 9 & 15] | 0), b = b + x + (l >>> 6 ^ l >>> 11 ^ l >>> 25 ^ l << 26 ^ l << 21 ^ l << 7) + (n ^ l & (w ^ n)) + i[a], x = n, n = w, w = l, l = r + b | 0, r = g, g = e, e = h, h = b + (e & g ^ r & (e ^ g)) + (e >>> 2 ^ e >>> 13 ^ e >>> 22 ^ e << 30 ^ e << 19 ^ e << 10) | 0;
d[0] = d[0] + h | 0;
d[1] = d[1] + e | 0;
d[2] = d[2] + g | 0;
d[3] = d[3] + r | 0;
d[4] = d[4] + l | 0;
d[5] = d[5] + w | 0;
d[6] = d[6] + n | 0;
d[7] = d[7] + x | 0
}
};
function K() {
var a = L,
b = 1024,
c;
c = "crypto['getRandomValues']";
var f, d, i = (new Date).valueOf(),
h = this.g[c],
e = this.o();
f = this.k[c];
f === j && (f = this.k[c] = this.r++);
h === j && (h = this.g[c] = 0);
this.g[c] = (this.g[c] + 1) % this.f.length;
switch (typeof a) {
case "number":
break;
case "object":
if (b === j) for (c = b = 0; c < a.length; c++) for (d = a[c]; 0 < d;) b++, d >>>= 1;
this.f[h].update([f, this.l++, 2, b, i, a.length].concat(a));
break;
case "string":
b === j && (b = a.length);
this.f[h].update([f, this.l++, 3, b, i, a.length]);
this.f[h].update(a);
break;
default:
throw new F;
}
this.p[h] += b;
this.j += b;
0 === e && (0 !== this.o() && this.m("seeded", Math.max(this.t, this.j)), this.m("progress", this.u()))
}
new J;
try {
var L = new Uint32Array(32);
k.v(L);
K()
} catch (M) {}
k = require("crypto");
require("util");
var N = 2147483647;
function scrypt(a, b, c, f, d, i) {
if (0 == c || 0 != (c & c - 1)) throw Error("N must be > 0 and a power of 2");
if (c > N / 128 / f) throw Error("Parameter N is too large");
if (f > N / 128 / d) throw Error("Parameter r is too large");
var h = [],
e = [],
g = [],
r = [];
PBKDF(a, new Buffer(b, encoding = "utf8"), e, 128 * d * f);
for (b = 0; b < d; b++) {
var l = e,
w = 128 * b * f,
n = f,
x = c,
O = r,
o = g,
u = 128 * n,
y = j;
E(l, w, o, 0, u);
for (y = 0; y < x; y++) E(o, 0, O, y * u, u), Q(o, u, n);
for (y = 0; y < x; y++) {
var z = 0,
v = j,
z = z + 64 * (2 * n - 1),
v = (o[z + 0] & 255) << 0,
v = v | (o[z + 1] & 255) << 8,
v = v | (o[z + 2] & 255) << 16,
v = v | (o[z + 3] & 255) << 24;
R(O, (v & x - 1) * u, o, u);
Q(o, u, n)
}
E(o, 0, l, w, u)
}
PBKDF(a, e, h, i);
return (new Buffer(h, "base64")).toString("base64")
}
function Q(a, b, c) {
var f = [],
d;
S(a, 0 + 64 * (2 * c - 1), f, 0);
for (d = 0; d < 2 * c; d++) {
R(a, 64 * d, f, 64);
for (var i = f, h = Array(32), e = Array(32), g = j, g = 0; 16 > g; g++) h[g] = (i[4 * g + 0] & 255) << 0, h[g] |= (i[4 * g + 1] & 255) << 8, h[g] |= (i[4 * g + 2] & 255) << 16, h[g] |= (i[4 * g + 3] & 255) << 24;
E(h, 0, e, 0, 16);
for (g = 8; 0 < g; g -= 2) e[4] ^= T(e[0] + e[12], 7), e[8] ^= T(e[4] + e[0], 9), e[12] ^= T(e[8] + e[4], 13), e[0] ^= T(e[12] + e[8], 18), e[9] ^= T(e[5] + e[1], 7), e[13] ^= T(e[9] + e[5], 9), e[1] ^= T(e[13] + e[9], 13), e[5] ^= T(e[1] + e[13], 18), e[14] ^= T(e[10] + e[6], 7), e[2] ^= T(e[14] + e[10], 9), e[6] ^= T(e[2] + e[14], 13), e[10] ^= T(e[6] + e[2], 18), e[3] ^= T(e[15] + e[11], 7), e[7] ^= T(e[3] + e[15], 9), e[11] ^= T(e[7] + e[3], 13), e[15] ^= T(e[11] + e[7], 18), e[1] ^= T(e[0] + e[3], 7), e[2] ^= T(e[1] + e[0], 9), e[3] ^= T(e[2] + e[1], 13), e[0] ^= T(e[3] + e[2], 18), e[6] ^= T(e[5] + e[4], 7), e[7] ^= T(e[6] + e[5], 9), e[4] ^= T(e[7] + e[6], 13), e[5] ^= T(e[4] + e[7], 18), e[11] ^= T(e[10] + e[9], 7), e[8] ^= T(e[11] + e[10], 9), e[9] ^= T(e[8] + e[11], 13), e[10] ^= T(e[9] + e[8], 18), e[12] ^= T(e[15] + e[14], 7), e[13] ^= T(e[12] + e[15], 9), e[14] ^= T(e[13] + e[12], 13), e[15] ^= T(e[14] + e[13], 18);
for (g = 0; 16 > g; ++g) h[g] = e[g] + h[g];
for (g = 0; 16 > g; g++) e = 4 * g, i[e + 0] = h[g] >> 0 & 255, i[e + 1] = h[g] >> 8 & 255, i[e + 2] = h[g] >> 16 & 255, i[e + 3] = h[g] >> 24 & 255;
S(f, 0, a, b + 64 * d)
}
for (d = 0; d < c; d++) S(a, b + 128 * d, a, 0 + 64 * d);
for (d = 0; d < c; d++) S(a, b + 64 * (2 * d + 1), a, 0 + 64 * (d + c))
}
function T(a, b) {
return a << b | a >>> 32 - b
}
function R(a, b, c, f) {
for (var d = 0, f = f >> 6; f--;) c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++], c[d++] ^= a[b++]
}
function E(a, b, c, f, d) {
for (; d--;) c[f++] = a[b++]
}
function scrypt(a, b, c, f) {
for (var d = 2; d--;) c[f++] = a[b++], c[f++] = a[b++], c[f++] = a[b++], c[f++] = a[b++], c[f++] = a[b++], c[f++] = a[b++], c[f++] = a[b++], c[f++] = a[b++], c[f++] = a[b++], c[f++] = a[b++], c[f++] = a[b++], c[f++] = a[b++], c[f++] = a[b++], c[f++] = a[b++], c[f++] = a[b++], c[f++] = a[b++], c[f++] = a[b++], c[f++] = a[b++], c[f++] = a[b++], c[f++] = a[b++], c[f++] = a[b++], c[f++] = a[b++], c[f++] = a[b++], c[f++] = a[b++], c[f++] = a[b++], c[f++] = a[b++], c[f++] = a[b++], c[f++] = a[b++], c[f++] = a[b++], c[f++] = a[b++], c[f++] = a[b++], c[f++] = a[b++]
}
exports.scrypt = P;
//scrypt("key", "salt", 32, 8, 4096, 32); // see
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment