OLD | NEW |
(Empty) | |
| 1 (function () { |
| 2 var /* |
| 3 * Rusha, a JavaScript implementation of the Secure Hash Algorithm, SHA-1, |
| 4 * as defined in FIPS PUB 180-1, tuned for high performance with large inputs. |
| 5 * (http://github.com/srijs/rusha) |
| 6 * |
| 7 * Inspired by Paul Johnstons implementation (http://pajhome.org.uk/crypt/md5). |
| 8 * |
| 9 * Copyright (c) 2013 Sam Rijs (http://awesam.de). |
| 10 * Released under the terms of the MIT license as follows: |
| 11 * |
| 12 * Permission is hereby granted, free of charge, to any person obtaining a |
| 13 * copy of this software and associated documentation files (the "Software"), |
| 14 * to deal in the Software without restriction, including without limitation |
| 15 * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| 16 * and/or sell copies of the Software, and to permit persons to whom the |
| 17 * Software is furnished to do so, subject to the following conditions: |
| 18 * |
| 19 * The above copyright notice and this permission notice shall be included in |
| 20 * all copies or substantial portions of the Software. |
| 21 * |
| 22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 23 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| 25 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 26 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
| 27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
| 28 * IN THE SOFTWARE. |
| 29 */ |
| 30 util = { |
| 31 getDataType: function (data) { |
| 32 if (typeof data === 'string') { |
| 33 return 'string'; |
| 34 } |
| 35 if (data instanceof Array) { |
| 36 return 'array'; |
| 37 } |
| 38 if (typeof global !== 'undefined' && global.Buffer && global.Buffer.
isBuffer(data)) { |
| 39 return 'buffer'; |
| 40 } |
| 41 if (data instanceof ArrayBuffer) { |
| 42 return 'arraybuffer'; |
| 43 } |
| 44 if (data.buffer instanceof ArrayBuffer) { |
| 45 return 'view'; |
| 46 } |
| 47 if (data instanceof Blob) { |
| 48 return 'blob'; |
| 49 } |
| 50 throw new Error('Unsupported data type.'); |
| 51 } |
| 52 }; |
| 53 function Rusha(chunkSize) { |
| 54 'use strict'; |
| 55 var // Private object structure. |
| 56 self$2 = { fill: 0 }; |
| 57 var // Calculate the length of buffer that the sha1 routine uses |
| 58 // including the padding. |
| 59 padlen = function (len) { |
| 60 for (len += 9; len % 64 > 0; len += 1); |
| 61 return len; |
| 62 }; |
| 63 var padZeroes = function (bin, len) { |
| 64 for (var i$2 = len >> 2; i$2 < bin.length; i$2++) |
| 65 bin[i$2] = 0; |
| 66 }; |
| 67 var padData = function (bin, chunkLen, msgLen) { |
| 68 bin[chunkLen >> 2] |= 128 << 24 - (chunkLen % 4 << 3); |
| 69 // To support msgLen >= 2 GiB, use a float division when computing t
he |
| 70 // high 32-bits of the big-endian message length in bits. |
| 71 bin[((chunkLen >> 2) + 2 & ~15) + 14] = msgLen / (1 << 29) | 0; |
| 72 bin[((chunkLen >> 2) + 2 & ~15) + 15] = msgLen << 3; |
| 73 }; |
| 74 var // Convert a binary string and write it to the heap. |
| 75 // A binary string is expected to only contain char codes < 256. |
| 76 convStr = function (H8, H32, start, len, off) { |
| 77 var str = this, i$2, om = off % 4, lm = len % 4, j = len - lm; |
| 78 if (j > 0) { |
| 79 switch (om) { |
| 80 case 0: |
| 81 H8[off + 3 | 0] = str.charCodeAt(start); |
| 82 case 1: |
| 83 H8[off + 2 | 0] = str.charCodeAt(start + 1); |
| 84 case 2: |
| 85 H8[off + 1 | 0] = str.charCodeAt(start + 2); |
| 86 case 3: |
| 87 H8[off | 0] = str.charCodeAt(start + 3); |
| 88 } |
| 89 } |
| 90 for (i$2 = om; i$2 < j; i$2 = i$2 + 4 | 0) { |
| 91 H32[off + i$2 >> 2] = str.charCodeAt(start + i$2) << 24 | str.ch
arCodeAt(start + i$2 + 1) << 16 | str.charCodeAt(start + i$2 + 2) << 8 | str.cha
rCodeAt(start + i$2 + 3); |
| 92 } |
| 93 switch (lm) { |
| 94 case 3: |
| 95 H8[off + j + 1 | 0] = str.charCodeAt(start + j + 2); |
| 96 case 2: |
| 97 H8[off + j + 2 | 0] = str.charCodeAt(start + j + 1); |
| 98 case 1: |
| 99 H8[off + j + 3 | 0] = str.charCodeAt(start + j); |
| 100 } |
| 101 }; |
| 102 var // Convert a buffer or array and write it to the heap. |
| 103 // The buffer or array is expected to only contain elements < 256. |
| 104 convBuf = function (H8, H32, start, len, off) { |
| 105 var buf = this, i$2, om = off % 4, lm = len % 4, j = len - lm; |
| 106 if (j > 0) { |
| 107 switch (om) { |
| 108 case 0: |
| 109 H8[off + 3 | 0] = buf[start]; |
| 110 case 1: |
| 111 H8[off + 2 | 0] = buf[start + 1]; |
| 112 case 2: |
| 113 H8[off + 1 | 0] = buf[start + 2]; |
| 114 case 3: |
| 115 H8[off | 0] = buf[start + 3]; |
| 116 } |
| 117 } |
| 118 for (i$2 = 4 - om; i$2 < j; i$2 = i$2 += 4 | 0) { |
| 119 H32[off + i$2 >> 2] = buf[start + i$2] << 24 | buf[start + i$2 +
1] << 16 | buf[start + i$2 + 2] << 8 | buf[start + i$2 + 3]; |
| 120 } |
| 121 switch (lm) { |
| 122 case 3: |
| 123 H8[off + j + 1 | 0] = buf[start + j + 2]; |
| 124 case 2: |
| 125 H8[off + j + 2 | 0] = buf[start + j + 1]; |
| 126 case 1: |
| 127 H8[off + j + 3 | 0] = buf[start + j]; |
| 128 } |
| 129 }; |
| 130 var convBlob = function (H8, H32, start, len, off) { |
| 131 var blob = this, i$2, om = off % 4, lm = len % 4, j = len - lm; |
| 132 var buf = new Uint8Array(reader.readAsArrayBuffer(blob.slice(start,
start + len))); |
| 133 if (j > 0) { |
| 134 switch (om) { |
| 135 case 0: |
| 136 H8[off + 3 | 0] = buf[0]; |
| 137 case 1: |
| 138 H8[off + 2 | 0] = buf[1]; |
| 139 case 2: |
| 140 H8[off + 1 | 0] = buf[2]; |
| 141 case 3: |
| 142 H8[off | 0] = buf[3]; |
| 143 } |
| 144 } |
| 145 for (i$2 = 4 - om; i$2 < j; i$2 = i$2 += 4 | 0) { |
| 146 H32[off + i$2 >> 2] = buf[i$2] << 24 | buf[i$2 + 1] << 16 | buf[
i$2 + 2] << 8 | buf[i$2 + 3]; |
| 147 } |
| 148 switch (lm) { |
| 149 case 3: |
| 150 H8[off + j + 1 | 0] = buf[j + 2]; |
| 151 case 2: |
| 152 H8[off + j + 2 | 0] = buf[j + 1]; |
| 153 case 1: |
| 154 H8[off + j + 3 | 0] = buf[j]; |
| 155 } |
| 156 }; |
| 157 var convFn = function (data) { |
| 158 switch (util.getDataType(data)) { |
| 159 case 'string': |
| 160 return convStr.bind(data); |
| 161 case 'array': |
| 162 return convBuf.bind(data); |
| 163 case 'buffer': |
| 164 return convBuf.bind(data); |
| 165 case 'arraybuffer': |
| 166 return convBuf.bind(new Uint8Array(data)); |
| 167 case 'view': |
| 168 return convBuf.bind(new Uint8Array(data.buffer, data.byteOffset,
data.byteLength)); |
| 169 case 'blob': |
| 170 return convBlob.bind(data); |
| 171 } |
| 172 }; |
| 173 var slice = function (data, offset) { |
| 174 switch (util.getDataType(data)) { |
| 175 case 'string': |
| 176 return data.slice(offset); |
| 177 case 'array': |
| 178 return data.slice(offset); |
| 179 case 'buffer': |
| 180 return data.slice(offset); |
| 181 case 'arraybuffer': |
| 182 return data.slice(offset); |
| 183 case 'view': |
| 184 return data.buffer.slice(offset); |
| 185 } |
| 186 }; |
| 187 var // Precompute 00 - ff strings |
| 188 precomputedHex = new Array(256); |
| 189 for (var i = 0; i < 256; i++) { |
| 190 precomputedHex[i] = (i < 16 ? '0' : '') + i.toString(16); |
| 191 } |
| 192 var // Convert an ArrayBuffer into its hexadecimal string representation
. |
| 193 hex = function (arrayBuffer) { |
| 194 var binarray = new Uint8Array(arrayBuffer); |
| 195 var res = new Array(arrayBuffer.byteLength); |
| 196 for (var i$2 = 0; i$2 < res.length; i$2++) { |
| 197 res[i$2] = precomputedHex[binarray[i$2]]; |
| 198 } |
| 199 return res.join(''); |
| 200 }; |
| 201 var ceilHeapSize = function (v) { |
| 202 // The asm.js spec says: |
| 203 // The heap object's byteLength must be either |
| 204 // 2^n for n in [12, 24) or 2^24 * n for n ≥ 1. |
| 205 // Also, byteLengths smaller than 2^16 are deprecated. |
| 206 var p; |
| 207 if (// If v is smaller than 2^16, the smallest possible solution |
| 208 // is 2^16. |
| 209 v <= 65536) |
| 210 return 65536; |
| 211 if (// If v < 2^24, we round up to 2^n, |
| 212 // otherwise we round up to 2^24 * n. |
| 213 v < 16777216) { |
| 214 for (p = 1; p < v; p = p << 1); |
| 215 } else { |
| 216 for (p = 16777216; p < v; p += 16777216); |
| 217 } |
| 218 return p; |
| 219 }; |
| 220 var // Initialize the internal data structures to a new capacity. |
| 221 init = function (size) { |
| 222 if (size % 64 > 0) { |
| 223 throw new Error('Chunk size must be a multiple of 128 bit'); |
| 224 } |
| 225 self$2.maxChunkLen = size; |
| 226 self$2.padMaxChunkLen = padlen(size); |
| 227 // The size of the heap is the sum of: |
| 228 // 1. The padded input message size |
| 229 // 2. The extended space the algorithm needs (320 byte) |
| 230 // 3. The 160 bit state the algoritm uses |
| 231 self$2.heap = new ArrayBuffer(ceilHeapSize(self$2.padMaxChunkLen + 3
20 + 20)); |
| 232 self$2.h32 = new Int32Array(self$2.heap); |
| 233 self$2.h8 = new Int8Array(self$2.heap); |
| 234 self$2.core = new Rusha._core({ |
| 235 Int32Array: Int32Array, |
| 236 DataView: DataView |
| 237 }, {}, self$2.heap); |
| 238 self$2.buffer = null; |
| 239 }; |
| 240 // Iinitializethe datastructures according |
| 241 // to a chunk siyze. |
| 242 init(chunkSize || 64 * 1024); |
| 243 var initState = function (heap, padMsgLen) { |
| 244 var io = new Int32Array(heap, padMsgLen + 320, 5); |
| 245 io[0] = 1732584193; |
| 246 io[1] = -271733879; |
| 247 io[2] = -1732584194; |
| 248 io[3] = 271733878; |
| 249 io[4] = -1009589776; |
| 250 }; |
| 251 var padChunk = function (chunkLen, msgLen) { |
| 252 var padChunkLen = padlen(chunkLen); |
| 253 var view = new Int32Array(self$2.heap, 0, padChunkLen >> 2); |
| 254 padZeroes(view, chunkLen); |
| 255 padData(view, chunkLen, msgLen); |
| 256 return padChunkLen; |
| 257 }; |
| 258 var // Write data to the heap. |
| 259 write = function (data, chunkOffset, chunkLen) { |
| 260 convFn(data)(self$2.h8, self$2.h32, chunkOffset, chunkLen, 0); |
| 261 }; |
| 262 var // Initialize and call the RushaCore, |
| 263 // assuming an input buffer of length len * 4. |
| 264 coreCall = function (data, chunkOffset, chunkLen, msgLen, finalize) { |
| 265 var padChunkLen = chunkLen; |
| 266 if (finalize) { |
| 267 padChunkLen = padChunk(chunkLen, msgLen); |
| 268 } |
| 269 write(data, chunkOffset, chunkLen); |
| 270 self$2.core.hash(padChunkLen, self$2.padMaxChunkLen); |
| 271 }; |
| 272 var getRawDigest = function (heap, padMaxChunkLen) { |
| 273 var io = new Int32Array(heap, padMaxChunkLen + 320, 5); |
| 274 var out = new Int32Array(5); |
| 275 var arr = new DataView(out.buffer); |
| 276 arr.setInt32(0, io[0], false); |
| 277 arr.setInt32(4, io[1], false); |
| 278 arr.setInt32(8, io[2], false); |
| 279 arr.setInt32(12, io[3], false); |
| 280 arr.setInt32(16, io[4], false); |
| 281 return out; |
| 282 }; |
| 283 var // Calculate the hash digest as an array of 5 32bit integers. |
| 284 rawDigest = this.rawDigest = function (str) { |
| 285 var msgLen = str.byteLength || str.length || str.size || 0; |
| 286 initState(self$2.heap, self$2.padMaxChunkLen); |
| 287 var chunkOffset = 0, chunkLen = self$2.maxChunkLen, last; |
| 288 for (chunkOffset = 0; msgLen > chunkOffset + chunkLen; chunkOffset +
= chunkLen) { |
| 289 coreCall(str, chunkOffset, chunkLen, msgLen, false); |
| 290 } |
| 291 coreCall(str, chunkOffset, msgLen - chunkOffset, msgLen, true); |
| 292 return getRawDigest(self$2.heap, self$2.padMaxChunkLen); |
| 293 }; |
| 294 // The digest and digestFrom* interface returns the hash digest |
| 295 // as a hex string. |
| 296 this.digest = this.digestFromString = this.digestFromBuffer = this.diges
tFromArrayBuffer = function (str) { |
| 297 return hex(rawDigest(str).buffer); |
| 298 }; |
| 299 } |
| 300 ; |
| 301 // The low-level RushCore module provides the heart of Rusha, |
| 302 // a high-speed sha1 implementation working on an Int32Array heap. |
| 303 // At first glance, the implementation seems complicated, however |
| 304 // with the SHA1 spec at hand, it is obvious this almost a textbook |
| 305 // implementation that has a few functions hand-inlined and a few loops |
| 306 // hand-unrolled. |
| 307 Rusha._core = function RushaCore(stdlib, foreign, heap) { |
| 308 'use asm'; |
| 309 var H = new stdlib.Int32Array(heap); |
| 310 function hash(k, x) { |
| 311 // k in bytes |
| 312 k = k | 0; |
| 313 x = x | 0; |
| 314 var i = 0, j = 0, y0 = 0, z0 = 0, y1 = 0, z1 = 0, y2 = 0, z2 = 0, y3
= 0, z3 = 0, y4 = 0, z4 = 0, t0 = 0, t1 = 0; |
| 315 y0 = H[x + 320 >> 2] | 0; |
| 316 y1 = H[x + 324 >> 2] | 0; |
| 317 y2 = H[x + 328 >> 2] | 0; |
| 318 y3 = H[x + 332 >> 2] | 0; |
| 319 y4 = H[x + 336 >> 2] | 0; |
| 320 for (i = 0; (i | 0) < (k | 0); i = i + 64 | 0) { |
| 321 z0 = y0; |
| 322 z1 = y1; |
| 323 z2 = y2; |
| 324 z3 = y3; |
| 325 z4 = y4; |
| 326 for (j = 0; (j | 0) < 64; j = j + 4 | 0) { |
| 327 t1 = H[i + j >> 2] | 0; |
| 328 t0 = ((y0 << 5 | y0 >>> 27) + (y1 & y2 | ~y1 & y3) | 0) + ((
t1 + y4 | 0) + 1518500249 | 0) | 0; |
| 329 y4 = y3; |
| 330 y3 = y2; |
| 331 y2 = y1 << 30 | y1 >>> 2; |
| 332 y1 = y0; |
| 333 y0 = t0; |
| 334 H[k + j >> 2] = t1; |
| 335 } |
| 336 for (j = k + 64 | 0; (j | 0) < (k + 80 | 0); j = j + 4 | 0) { |
| 337 t1 = (H[j - 12 >> 2] ^ H[j - 32 >> 2] ^ H[j - 56 >> 2] ^ H[j
- 64 >> 2]) << 1 | (H[j - 12 >> 2] ^ H[j - 32 >> 2] ^ H[j - 56 >> 2] ^ H[j - 64
>> 2]) >>> 31; |
| 338 t0 = ((y0 << 5 | y0 >>> 27) + (y1 & y2 | ~y1 & y3) | 0) + ((
t1 + y4 | 0) + 1518500249 | 0) | 0; |
| 339 y4 = y3; |
| 340 y3 = y2; |
| 341 y2 = y1 << 30 | y1 >>> 2; |
| 342 y1 = y0; |
| 343 y0 = t0; |
| 344 H[j >> 2] = t1; |
| 345 } |
| 346 for (j = k + 80 | 0; (j | 0) < (k + 160 | 0); j = j + 4 | 0) { |
| 347 t1 = (H[j - 12 >> 2] ^ H[j - 32 >> 2] ^ H[j - 56 >> 2] ^ H[j
- 64 >> 2]) << 1 | (H[j - 12 >> 2] ^ H[j - 32 >> 2] ^ H[j - 56 >> 2] ^ H[j - 64
>> 2]) >>> 31; |
| 348 t0 = ((y0 << 5 | y0 >>> 27) + (y1 ^ y2 ^ y3) | 0) + ((t1 + y
4 | 0) + 1859775393 | 0) | 0; |
| 349 y4 = y3; |
| 350 y3 = y2; |
| 351 y2 = y1 << 30 | y1 >>> 2; |
| 352 y1 = y0; |
| 353 y0 = t0; |
| 354 H[j >> 2] = t1; |
| 355 } |
| 356 for (j = k + 160 | 0; (j | 0) < (k + 240 | 0); j = j + 4 | 0) { |
| 357 t1 = (H[j - 12 >> 2] ^ H[j - 32 >> 2] ^ H[j - 56 >> 2] ^ H[j
- 64 >> 2]) << 1 | (H[j - 12 >> 2] ^ H[j - 32 >> 2] ^ H[j - 56 >> 2] ^ H[j - 64
>> 2]) >>> 31; |
| 358 t0 = ((y0 << 5 | y0 >>> 27) + (y1 & y2 | y1 & y3 | y2 & y3)
| 0) + ((t1 + y4 | 0) - 1894007588 | 0) | 0; |
| 359 y4 = y3; |
| 360 y3 = y2; |
| 361 y2 = y1 << 30 | y1 >>> 2; |
| 362 y1 = y0; |
| 363 y0 = t0; |
| 364 H[j >> 2] = t1; |
| 365 } |
| 366 for (j = k + 240 | 0; (j | 0) < (k + 320 | 0); j = j + 4 | 0) { |
| 367 t1 = (H[j - 12 >> 2] ^ H[j - 32 >> 2] ^ H[j - 56 >> 2] ^ H[j
- 64 >> 2]) << 1 | (H[j - 12 >> 2] ^ H[j - 32 >> 2] ^ H[j - 56 >> 2] ^ H[j - 64
>> 2]) >>> 31; |
| 368 t0 = ((y0 << 5 | y0 >>> 27) + (y1 ^ y2 ^ y3) | 0) + ((t1 + y
4 | 0) - 899497514 | 0) | 0; |
| 369 y4 = y3; |
| 370 y3 = y2; |
| 371 y2 = y1 << 30 | y1 >>> 2; |
| 372 y1 = y0; |
| 373 y0 = t0; |
| 374 H[j >> 2] = t1; |
| 375 } |
| 376 y0 = y0 + z0 | 0; |
| 377 y1 = y1 + z1 | 0; |
| 378 y2 = y2 + z2 | 0; |
| 379 y3 = y3 + z3 | 0; |
| 380 y4 = y4 + z4 | 0; |
| 381 } |
| 382 H[x + 320 >> 2] = y0; |
| 383 H[x + 324 >> 2] = y1; |
| 384 H[x + 328 >> 2] = y2; |
| 385 H[x + 332 >> 2] = y3; |
| 386 H[x + 336 >> 2] = y4; |
| 387 } |
| 388 return { hash: hash }; |
| 389 }; |
| 390 exports = Rusha; |
| 391 if (// If we'e running in Node.JS, export a module. |
| 392 typeof module !== 'undefined') { |
| 393 module.exports = Rusha; |
| 394 } else {// If we're running in Adblock Plus, export a module. |
| 395 exports = Rusha; |
| 396 } |
| 397 if (// If we're running in a webworker, accept |
| 398 // messages containing a jobid and a buffer |
| 399 // or blob object, and return the hash result. |
| 400 typeof FileReaderSync !== 'undefined') { |
| 401 var reader = new FileReaderSync(), hasher = new Rusha(4 * 1024 * 1024); |
| 402 self.onmessage = function onMessage(event) { |
| 403 var hash, data = event.data.data; |
| 404 try { |
| 405 hash = hasher.digest(data); |
| 406 self.postMessage({ |
| 407 id: event.data.id, |
| 408 hash: hash |
| 409 }); |
| 410 } catch (e) { |
| 411 self.postMessage({ |
| 412 id: event.data.id, |
| 413 error: e.name |
| 414 }); |
| 415 } |
| 416 }; |
| 417 } |
| 418 }()); |
OLD | NEW |