SHA512 optimizations

This commit is contained in:
Yury Delendik 2014-06-13 15:12:50 -05:00
parent 1fce2856c6
commit dd165f2918

View File

@ -147,64 +147,87 @@ var calculateMD5 = (function calculateMD5Closure() {
})(); })();
var Word64 = (function Word64Closure() { var Word64 = (function Word64Closure() {
function Word64(highInteger, lowInteger) { function Word64(highInteger, lowInteger) {
this.low = lowInteger >>> 0; this.high = highInteger | 0;
this.high = highInteger >>> 0; this.low = lowInteger | 0;
} }
Word64.prototype = { Word64.prototype = {
and: function Word64_and(word) { and: function Word64_and(word) {
return new Word64(this.high & word.high, this.high &= word.high;
this.low & word.low); this.low &= word.low;
}, },
xor: function Word64_xor(word) { xor: function Word64_xor(word) {
return new Word64(this.high ^ word.high, this.high ^= word.high;
this.low ^ word.low); this.low ^= word.low;
}, },
or: function Word64_or(word) { or: function Word64_or(word) {
return new Word64(this.high | word.high, this.high |= word.high;
this.low | word.low); this.low |= word.low;
}, },
shiftRight: function Word64_shiftRight(places) { shiftRight: function Word64_shiftRight(places) {
if (places >= 32) { if (places >= 32) {
return new Word64(0x00000000, this.high >>> (places - 32)); this.low = (this.high >>> (places - 32)) | 0;
this.high = 0;
} else {
this.low = (this.low >>> places) | (this.high << (32 - places));
this.high = (this.high >>> places) | 0;
} }
return new Word64(this.high >>> places,
(this.low >>> places) | (this.high << 32 - places));
}, },
shiftLeft: function Word64_shiftLeft(places) { shiftLeft: function Word64_shiftLeft(places) {
if (places >= 32) { if (places >= 32) {
return new Word64(this.low << (places - 32), 0x00000000); this.high = this.low << (places - 32);
this.low = 0;
} else {
this.high = (this.high << places) | (this.low >>> (32 - places));
this.low = this.low << places;
} }
return new Word64((this.high << places) |
(this.low >>> 32 - places),
(this.low << places));
}, },
rotateRight: function Word64_rotateRight(places) {
var low, high;
if (places & 32) {
high = this.low;
low = this.high;
} else {
low = this.low;
high = this.high;
}
places &= 31;
this.low = (low >>> places) | (high << (32 - places));
this.high = (high >>> places) | (low << (32 - places));
},
not: function Word64_not() { not: function Word64_not() {
return new Word64(~this.high, ~this.low); this.high = ~this.high;
this.low = ~this.low;
}, },
plus: function Word64_plus(word) {
var lowAdd = this.low + word.low; add: function Word64_add(word) {
var highAdd = this.high + word.high; var lowAdd = (this.low >>> 0) + (word.low >>> 0);
var highAdd = (this.high >>> 0) + (word.high >>> 0);
if (lowAdd > 0xFFFFFFFF) { if (lowAdd > 0xFFFFFFFF) {
highAdd += 1; highAdd += 1;
} }
return new Word64((highAdd | 0) >>> 0, this.low = lowAdd | 0;
(lowAdd | 0) >>> 0); this.high = highAdd | 0;
}, },
copyTo: function Word64_copyTo(bytes, offset) { copyTo: function Word64_copyTo(bytes, offset) {
if (offset + bytes >= bytes.length) {
error('insufficient byte array length');
}
bytes[offset] = (this.high >>> 24) & 0xFF; bytes[offset] = (this.high >>> 24) & 0xFF;
bytes[offset + 1] = (this.high >>> 16) & 0xFF; bytes[offset + 1] = (this.high >> 16) & 0xFF;
bytes[offset + 2] = (this.high >>> 8) & 0xFF; bytes[offset + 2] = (this.high >> 8) & 0xFF;
bytes[offset + 3] = (this.high) & 0xFF; bytes[offset + 3] = this.high & 0xFF;
bytes[offset + 4] = (this.low >>> 24) & 0xFF; bytes[offset + 4] = (this.low >>> 24) & 0xFF;
bytes[offset + 5] = (this.low >>> 16) & 0xFF; bytes[offset + 5] = (this.low >> 16) & 0xFF;
bytes[offset + 6] = (this.low >>> 8) & 0xFF; bytes[offset + 6] = (this.low >> 8) & 0xFF;
bytes[offset + 7] = (this.low) & 0xFF; bytes[offset + 7] = this.low & 0xFF;
},
assign: function Word64_assign(word) {
this.high = word.high;
this.low = word.low;
} }
}; };
return Word64; return Word64;
@ -282,17 +305,17 @@ var calculateSHA256 = (function calculateSHA256Closure() {
padded[i++] = (length >> 5) & 0xFF; padded[i++] = (length >> 5) & 0xFF;
padded[i++] = (length << 3) & 0xFF; padded[i++] = (length << 3) & 0xFF;
var w = new Uint32Array(64); var w = new Uint32Array(64);
//for each 512 bit block // for each 512 bit block
for (i = 0; i < paddedLength;) { for (i = 0; i < paddedLength;) {
for (j = 0; j < 64; ++j) { for (j = 0; j < 16; ++j) {
if (j < 16) { w[j] = (padded[i] << 24 | (padded[i + 1] << 16) |
w[j] = (padded[i] << 24 | (padded[i + 1] << 16) | (padded[i + 2] << 8) | (padded[i + 3]));
(padded[i + 2] << 8) | (padded[i + 3])); i += 4;
i += 4; }
} else {
w[j] = littleSigmaPrime(w[j - 2]) + w[j - 7] + for (j = 16; j < 64; ++j) {
littleSigma(w[j - 15]) + w[j - 16] | 0; w[j] = littleSigmaPrime(w[j - 2]) + w[j - 7] +
} littleSigma(w[j - 15]) + w[j - 16] | 0;
} }
var a = h0, b = h1, c = h2, d = h3, e = h4, var a = h0, b = h1, c = h2, d = h3, e = h4,
f = h5, g = h6, h = h7, t1, t2; f = h5, g = h6, h = h7, t1, t2;
@ -333,32 +356,68 @@ var calculateSHA256 = (function calculateSHA256Closure() {
})(); })();
var calculateSHA512 = (function calculateSHA512Closure() { var calculateSHA512 = (function calculateSHA512Closure() {
function rotr(x, n) { function ch(result, x, y, z, tmp) {
return (x.shiftRight(n)).or(x.shiftLeft(64 - n)); result.assign(x);
result.and(y);
tmp.assign(x);
tmp.not();
tmp.and(z);
result.xor(tmp);
} }
function ch(x, y, z) { function maj(result, x, y, z, tmp) {
return (x.and(y)).xor(x.not().and(z)); result.assign(x);
result.and(y);
tmp.assign(x);
tmp.and(z);
result.xor(tmp);
tmp.assign(y);
tmp.and(z);
result.xor(tmp);
} }
function maj(x, y, z) { function sigma(result, x, tmp) {
return (x.and(y)).xor(x.and(z)).xor(y.and(z)); result.assign(x);
result.rotateRight(28);
tmp.assign(x);
tmp.rotateRight(34);
result.xor(tmp);
tmp.assign(x);
tmp.rotateRight(39);
result.xor(tmp);
} }
function sigma(x) { function sigmaPrime(result, x, tmp) {
return rotr(x, 28).xor(rotr(x, 34)).xor(rotr(x, 39)); result.assign(x);
result.rotateRight(14);
tmp.assign(x);
tmp.rotateRight(18);
result.xor(tmp);
tmp.assign(x);
tmp.rotateRight(41);
result.xor(tmp);
} }
function sigmaPrime(x) { function littleSigma(result, x, tmp) {
return rotr(x, 14).xor(rotr(x, 18)).xor(rotr(x, 41)); result.assign(x);
result.rotateRight(1);
tmp.assign(x);
tmp.rotateRight(8);
result.xor(tmp);
tmp.assign(x);
tmp.shiftRight(7);
result.xor(tmp);
} }
function littleSigma(x) { function littleSigmaPrime(result, x, tmp) {
return rotr(x, 1).xor(rotr(x, 8)).xor(x.shiftRight(7)); result.assign(x);
} result.rotateRight(19);
tmp.assign(x);
function littleSigmaPrime(x) { tmp.rotateRight(61);
return rotr(x, 19).xor(rotr(x, 61)).xor(x.shiftRight(6)); result.xor(tmp);
tmp.assign(x);
tmp.shiftRight(6);
result.xor(tmp);
} }
var k = [ var k = [
@ -418,8 +477,8 @@ var calculateSHA512 = (function calculateSHA512Closure() {
h7 = new Word64(0x5be0cd19, 0x137e2179); h7 = new Word64(0x5be0cd19, 0x137e2179);
} }
else { else {
//SHA384 is exactly the same // SHA384 is exactly the same
//except with different starting values and a trimmed result // except with different starting values and a trimmed result
h0 = new Word64(0xcbbb9d5d, 0xc1059ed8); h0 = new Word64(0xcbbb9d5d, 0xc1059ed8);
h1 = new Word64(0x629a292a, 0x367cd507); h1 = new Word64(0x629a292a, 0x367cd507);
h2 = new Word64(0x9159015a, 0x3070dd17); h2 = new Word64(0x9159015a, 0x3070dd17);
@ -459,51 +518,70 @@ var calculateSHA512 = (function calculateSHA512Closure() {
padded[i++] = (length >> 5) & 0xFF; padded[i++] = (length >> 5) & 0xFF;
padded[i++] = (length << 3) & 0xFF; padded[i++] = (length << 3) & 0xFF;
var w = new Array(128); var w = new Array(80);
//for each 1024 bit block for (i = 0; i < 80; i++) {
for (i = 0; i < paddedLength;) { w[i] = new Word64(0, 0);
for (j = 0; j < 80; ++j) { }
if (j < 16) { var a = new Word64(0, 0), b = new Word64(0, 0), c = new Word64(0, 0);
var value = new Word64(padded[i] << 24 |(padded[i + 1] << 16) | var d = new Word64(0, 0), e = new Word64(0, 0), f = new Word64(0, 0);
(padded[i + 2] << 8) | (padded[i + 3]), var g = new Word64(0, 0), h = new Word64(0, 0);
(padded[i + 4]) << 24 | (padded[i + 5]) << 16 | var t1 = new Word64(0, 0), t2 = new Word64(0, 0);
(padded[i + 6]) << 8 | (padded[i + 7])); var tmp1 = new Word64(0, 0), tmp2 = new Word64(0, 0), tmp3;
w[j] = value;
i += 8;
} else {
w[j] = littleSigmaPrime(w[j - 2])
.plus(w[j - 7])
.plus(littleSigma(w[j - 15]))
.plus(w[j - 16]);
}
// for each 1024 bit block
for (i = 0; i < paddedLength;) {
for (j = 0; j < 16; ++j) {
w[j].high = (padded[i] << 24) | (padded[i + 1] << 16) |
(padded[i + 2] << 8) | (padded[i + 3]);
w[j].low = (padded[i + 4]) << 24 | (padded[i + 5]) << 16 |
(padded[i + 6]) << 8 | (padded[i + 7]);
i += 8;
} }
var a = h0, b = h1, c = h2, d = h3, for (j = 16; j < 80; ++j) {
e = h4, f = h5, g = h6, h = h7, tmp3 = w[j];
t1, t2; littleSigmaPrime(tmp3, w[j - 2], tmp2);
tmp3.add(w[j - 7]);
littleSigma(tmp1, w[j - 15], tmp2);
tmp3.add(tmp1);
tmp3.add(w[j - 16]);
}
a.assign(h0); b.assign(h1); c.assign(h2); d.assign(h3);
e.assign(h4); f.assign(h5); g.assign(h6); h.assign(h7);
for (j = 0; j < 80; ++j) { for (j = 0; j < 80; ++j) {
t1 = h.plus(sigmaPrime(e)) t1.assign(h);
.plus(ch(e, f, g)) sigmaPrime(tmp1, e, tmp2);
.plus(k[j]) t1.add(tmp1);
.plus(w[j]); ch(tmp1, e, f, g, tmp2);
t2 = sigma(a).plus(maj(a, b, c)); t1.add(tmp1);
t1.add(k[j]);
t1.add(w[j]);
sigma(t2, a, tmp2);
maj(tmp1, a, b, c, tmp2);
t2.add(tmp1);
tmp3 = h;
h = g; h = g;
g = f; g = f;
f = e; f = e;
e = (d.plus(t1)); d.add(t1);
e = d;
d = c; d = c;
c = b; c = b;
b = a; b = a;
a = (t1.plus(t2)); tmp3.assign(t1);
tmp3.add(t2);
a = tmp3;
} }
h0 = (h0.plus(a)); h0.add(a);
h1 = (h1.plus(b)); h1.add(b);
h2 = (h2.plus(c)); h2.add(c);
h3 = (h3.plus(d)); h3.add(d);
h4 = (h4.plus(e)); h4.add(e);
h5 = (h5.plus(f)); h5.add(f);
h6 = (h6.plus(g)); h6.add(g);
h7 = (h7.plus(h)); h7.add(h);
} }
var result; var result;
@ -1421,7 +1499,7 @@ var AES256Cipher = (function AES256CipherClosure() {
return AES256Cipher; return AES256Cipher;
})(); })();
var PDF17= (function PDF17Closure() { var PDF17 = (function PDF17Closure() {
function compareByteArrays(array1, array2) { function compareByteArrays(array1, array2) {
if (array1.length !== array2.length) { if (array1.length !== array2.length) {