Skip to content
This repository was archived by the owner on Feb 5, 2020. It is now read-only.

Commit 4ee0aac

Browse files
committed
Speed up hashing in browsers.
Avoid deopts by remaining inside of string boundaries.
1 parent 9af969a commit 4ee0aac

File tree

1 file changed

+19
-22
lines changed

1 file changed

+19
-22
lines changed

lib/browser/crypto.js

Lines changed: 19 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,49 +12,46 @@ exports.createHash = function () {
1212
/*! @license MIT ©2002-2014 Chris Veness */
1313
/* SHA-1 implementation */
1414

15+
// constants [§4.2.1]
16+
var K = [0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6];
17+
var pow2to35 = Math.pow(2, 35);
18+
1519
/**
1620
* Generates SHA-1 hash of string.
1721
*
1822
* @param {string} msg - (Unicode) string to be hashed.
1923
* @returns {string} Hash of msg as hex character string.
2024
*/
2125
function sha1(msg) {
22-
// constants [§4.2.1]
23-
var K = [0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6], i, j;
24-
2526
// PREPROCESSING
26-
msg += String.fromCharCode(0x80); // add trailing '1' bit (+ 0's padding) to string [§5.1.1]
27+
msg += '\u0080'; // add trailing '1' bit (+ 0's padding) to string [§5.1.1]
2728

2829
// convert string msg into 512-bit/16-integer blocks arrays of ints [§5.2.1]
29-
var l = msg.length / 4 + 2; // length (in 32-bit integers) of msg + ‘1’ + appended length
30-
var N = Math.ceil(l / 16); // number of 16-integer-blocks required to hold 'l' ints
30+
var length = msg.length;
31+
var l = length / 4 + 2; // length (in 32-bit integers) of msg + ‘1’ + appended length
32+
var N = ~~((l + 15) / 16); // number of 16-integer-blocks required to hold 'l' ints
3133
var M = new Array(N);
3234

33-
for (i = 0; i < N; i++) {
35+
var i, j, index;
36+
for (i = 0, index = 0; i < N; i++) {
3437
M[i] = new Array(16);
35-
for (j = 0; j < 16; j++) { // encode 4 chars per integer, big-endian encoding
36-
M[i][j] = (msg.charCodeAt(i * 64 + j * 4) << 24) |
37-
(msg.charCodeAt(i * 64 + j * 4 + 1) << 16) |
38-
(msg.charCodeAt(i * 64 + j * 4 + 2) << 8) |
39-
(msg.charCodeAt(i * 64 + j * 4 + 3));
40-
} // note running off the end of msg is ok 'cos bitwise ops on NaN return 0
38+
for (j = 0; j < 16; j++, index++) { // encode 4 chars per integer, big-endian encoding
39+
M[i][j] = (index < length ? msg.charCodeAt(index) << 24 : 0) |
40+
(++index < length ? msg.charCodeAt(index) << 16 : 0) |
41+
(++index < length ? msg.charCodeAt(index) << 8 : 0) |
42+
(++index < length ? msg.charCodeAt(index) : 0);
43+
}
4144
}
4245
// add length (in bits) into final pair of 32-bit integers (big-endian) [§5.1.1]
4346
// note: most significant word would be (len-1)*8 >>> 32, but since JS converts
4447
// bitwise-op args to 32 bits, we need to simulate this by arithmetic operators
45-
M[N - 1][14] = ((msg.length - 1) * 8) / Math.pow(2, 32);
46-
M[N - 1][14] = Math.floor(M[N - 1][14]);
48+
M[N - 1][14] = ~~((msg.length - 1) / pow2to35);
4749
M[N - 1][15] = ((msg.length - 1) * 8) & 0xffffffff;
4850

4951
// set initial hash value [§5.3.1]
50-
var H0 = 0x67452301;
51-
var H1 = 0xefcdab89;
52-
var H2 = 0x98badcfe;
53-
var H3 = 0x10325476;
54-
var H4 = 0xc3d2e1f0;
52+
var H0 = 0x67452301, H1 = 0xefcdab89, H2 = 0x98badcfe, H3 = 0x10325476, H4 = 0xc3d2e1f0;
5553

5654
// HASH COMPUTATION [§6.1.2]
57-
5855
var W = new Array(80), a, b, c, d, e, t;
5956
for (i = 0; i < N; i++) {
6057
// 1 - prepare message schedule 'W'
@@ -66,7 +63,7 @@ function sha1(msg) {
6663

6764
// 3 - main loop
6865
for (t = 0; t < 80; t++) {
69-
var s = Math.floor(t / 20); // seq for blocks of 'f' functions and 'K' constants
66+
var s = ~~(t / 20); // seq for blocks of 'f' functions and 'K' constants
7067
var T = (rotl(a, 5) + f(s, b, c, d) + e + K[s] + W[t]) & 0xffffffff;
7168
e = d;
7269
d = c;

0 commit comments

Comments
 (0)