diff --git a/app/index.html b/app/index.html
index 7d437a38..df7d7019 100644
--- a/app/index.html
+++ b/app/index.html
@@ -56,6 +56,7 @@
+
diff --git a/app/js/lib/bin_utils.js b/app/js/lib/bin_utils.js
index 38bbf77f..ecbfdfd4 100644
--- a/app/js/lib/bin_utils.js
+++ b/app/js/lib/bin_utils.js
@@ -196,9 +196,10 @@ function uintToInt (val) {
}
function sha1Hash (bytes) {
- // console.log('SHA-1 hash start');
- var hashBytes = sha1.hash(bytes, true);
- // console.log('SHA-1 hash finish');
+ this.rushaInstance = this.rushaInstance || new Rusha(1024 * 1024);
+ // console.log(dT(), 'SHA-1 hash start', bytes.byteLength || bytes.length);
+ var hashBytes = bytesFromArrayBuffer(rushaInstance.rawDigest(bytes).buffer);
+ // console.log(dT(), 'SHA-1 hash finish');
return hashBytes;
}
diff --git a/app/js/lib/crypto_worker.js b/app/js/lib/crypto_worker.js
index 3340a9d6..2f42cf55 100644
--- a/app/js/lib/crypto_worker.js
+++ b/app/js/lib/crypto_worker.js
@@ -11,7 +11,8 @@ importScripts(
'../../vendor/jsbn/jsbn_combined.js',
'../../vendor/leemon_bigint/bigint.js',
'../../vendor/closure/long.js',
- '../../vendor/cryptoJS/crypto.js'
+ '../../vendor/cryptoJS/crypto.js',
+ '../../vendor/rusha/rusha.js'
);
onmessage = function (e) {
diff --git a/app/js/lib/tl_utils.js b/app/js/lib/tl_utils.js
index a94f6651..18c736b2 100644
--- a/app/js/lib/tl_utils.js
+++ b/app/js/lib/tl_utils.js
@@ -36,7 +36,16 @@ TLSerialization.prototype.getBuffer = function () {
return this.getArray().buffer;
};
-TLSerialization.prototype.getBytes = function () {
+TLSerialization.prototype.getBytes = function (typed) {
+ if (typed) {
+ var resultBuffer = new ArrayBuffer(this.offset);
+ var resultArray = new Uint8Array(resultBuffer);
+
+ resultArray.set(this.byteView.subarray(0, this.offset));
+
+ return resultArray;
+ }
+
var bytes = [];
for (var i = 0; i < this.offset; i++) {
bytes.push(this.byteView[i]);
@@ -141,9 +150,8 @@ TLSerialization.prototype.storeString = function (s, field) {
TLSerialization.prototype.storeBytes = function (bytes, field) {
this.debug && console.log('>>>', bytesToHex(bytes), (field || '') + ':bytes');
- this.checkLength(bytes.length + 8);
-
- var len = bytes.length;
+ var len = bytes.byteLength || bytes.length;
+ this.checkLength(len + 8);
if (len <= 253) {
this.byteView[this.offset++] = len;
} else {
@@ -152,9 +160,8 @@ TLSerialization.prototype.storeBytes = function (bytes, field) {
this.byteView[this.offset++] = (len & 0xFF00) >> 8;
this.byteView[this.offset++] = (len & 0xFF0000) >> 16;
}
- for (var i = 0; i < len; i++) {
- this.byteView[this.offset++] = bytes[i];
- }
+ this.byteView.set(bytes, this.offset);
+ this.offset += len;
// Padding
while (this.offset % 4) {
@@ -177,14 +184,13 @@ TLSerialization.prototype.storeIntBytes = function (bytes, bits, field) {
};
TLSerialization.prototype.storeRawBytes = function (bytes, field) {
- var len = bytes.length;
+ var len = bytes.byteLength || bytes.length;
this.debug && console.log('>>>', bytesToHex(bytes), (field || ''));
this.checkLength(len);
- for (var i = 0; i < len; i++) {
- this.byteView[this.offset++] = bytes[i];
- }
+ this.byteView.set(bytes, this.offset);
+ this.offset += len;
};
diff --git a/app/vendor/rusha/rusha.js b/app/vendor/rusha/rusha.js
new file mode 100644
index 00000000..dd550de0
--- /dev/null
+++ b/app/vendor/rusha/rusha.js
@@ -0,0 +1,392 @@
+/*
+ * Rusha, a JavaScript implementation of the Secure Hash Algorithm, SHA-1,
+ * as defined in FIPS PUB 180-1, tuned for high performance with large inputs.
+ * (http://github.com/srijs/rusha)
+ *
+ * Inspired by Paul Johnstons implementation (http://pajhome.org.uk/crypt/md5).
+ *
+ * Copyright (c) 2013 Sam Rijs (http://awesam.de).
+ * Released under the terms of the MIT license as follows:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+(function (global) {
+ // If we'e running in Node.JS, export a module.
+ if (typeof module !== 'undefined') {
+ module.exports = Rusha;
+ }
+ // If we're running in a DOM context, export
+ // the Rusha object to toplevel.
+ if (typeof global !== 'undefined') {
+ global.Rusha = Rusha;
+ }
+ // If we're running in a webworker, accept
+ // messages containing a jobid and a buffer
+ // or blob object, and return the hash result.
+ if (typeof FileReaderSync !== 'undefined') {
+ var reader = new FileReaderSync(), hasher = new Rusha(4 * 1024 * 1024);
+ self.onmessage = function onMessage(event) {
+ var hash, data = event.data.data;
+ if (data instanceof Blob) {
+ try {
+ data = reader.readAsBinaryString(data);
+ } catch (e) {
+ self.postMessage({
+ id: event.data.id,
+ error: e.name
+ });
+ return;
+ }
+ }
+ hash = hasher.digest(data);
+ self.postMessage({
+ id: event.data.id,
+ hash: hash
+ });
+ };
+ }
+ var util = {
+ getDataType: function (data) {
+ if (typeof data === 'string') {
+ return 'string';
+ }
+ if (data instanceof Array) {
+ return 'array';
+ }
+ if (typeof global !== 'undefined' && global.Buffer && global.Buffer.isBuffer(data)) {
+ return 'buffer';
+ }
+ if (data instanceof ArrayBuffer) {
+ return 'arraybuffer';
+ }
+ if (data.buffer instanceof ArrayBuffer) {
+ return 'view';
+ }
+ throw new Error('Unsupported data type.');
+ }
+ };
+ // The Rusha object is a wrapper around the low-level RushaCore.
+ // It provides means of converting different inputs to the
+ // format accepted by RushaCore as well as other utility methods.
+ function Rusha(chunkSize) {
+ 'use strict';
+ // Private object structure.
+ var self$2 = { fill: 0 };
+ // Calculate the length of buffer that the sha1 routine uses
+ // including the padding.
+ var padlen = function (len) {
+ for (len += 9; len % 64 > 0; len += 1);
+ return len;
+ };
+ var padZeroes = function (bin, len) {
+ for (var i = len >> 2; i < bin.length; i++)
+ bin[i] = 0;
+ };
+ var padData = function (bin, chunkLen, msgLen) {
+ bin[chunkLen >> 2] |= 128 << 24 - (chunkLen % 4 << 3);
+ bin[((chunkLen >> 2) + 2 & ~15) + 15] = msgLen << 3;
+ };
+ // Convert a binary string and write it to the heap.
+ // A binary string is expected to only contain char codes < 256.
+ var convStr = function (H8, H32, start, len, off) {
+ var str = this, i, om = off % 4, lm = len % 4, j = len - lm;
+ if (j > 0) {
+ switch (om) {
+ case 0:
+ H8[off + 3 | 0] = str.charCodeAt(start);
+ case 1:
+ H8[off + 2 | 0] = str.charCodeAt(start + 1);
+ case 2:
+ H8[off + 1 | 0] = str.charCodeAt(start + 2);
+ case 3:
+ H8[off | 0] = str.charCodeAt(start + 3);
+ }
+ }
+ for (i = om; i < j; i = i + 4 | 0) {
+ H32[off + i >> 2] = str.charCodeAt(start + i) << 24 | str.charCodeAt(start + i + 1) << 16 | str.charCodeAt(start + i + 2) << 8 | str.charCodeAt(start + i + 3);
+ }
+ switch (lm) {
+ case 3:
+ H8[off + j + 1 | 0] = str.charCodeAt(start + j + 2);
+ case 2:
+ H8[off + j + 2 | 0] = str.charCodeAt(start + j + 1);
+ case 1:
+ H8[off + j + 3 | 0] = str.charCodeAt(start + j);
+ }
+ };
+ // Convert a buffer or array and write it to the heap.
+ // The buffer or array is expected to only contain elements < 256.
+ var convBuf = function (H8, H32, start, len, off) {
+ var buf = this, i, om = off % 4, lm = len % 4, j = len - lm;
+ if (j > 0) {
+ switch (om) {
+ case 0:
+ H8[off + 3 | 0] = buf[start];
+ case 1:
+ H8[off + 2 | 0] = buf[start + 1];
+ case 2:
+ H8[off + 1 | 0] = buf[start + 2];
+ case 3:
+ H8[off | 0] = buf[start + 3];
+ }
+ }
+ for (i = 4 - om; i < j; i = i += 4 | 0) {
+ H32[off + i >> 2] = buf[start + i] << 24 | buf[start + i + 1] << 16 | buf[start + i + 2] << 8 | buf[start + i + 3];
+ }
+ switch (lm) {
+ case 3:
+ H8[off + j + 1 | 0] = buf[start + j + 2];
+ case 2:
+ H8[off + j + 2 | 0] = buf[start + j + 1];
+ case 1:
+ H8[off + j + 3 | 0] = buf[start + j];
+ }
+ };
+ var convFn = function (data) {
+ switch (util.getDataType(data)) {
+ case 'string':
+ return convStr.bind(data);
+ case 'array':
+ return convBuf.bind(data);
+ case 'buffer':
+ return convBuf.bind(data);
+ case 'arraybuffer':
+ return convBuf.bind(new Uint8Array(data));
+ case 'view':
+ return convBuf.bind(new Uint8Array(data.buffer));
+ }
+ };
+ var slice = function (data, offset) {
+ switch (util.getDataType(data)) {
+ case 'string':
+ return data.slice(offset);
+ case 'array':
+ return data.slice(offset);
+ case 'buffer':
+ return data.slice(offset);
+ case 'arraybuffer':
+ return data.slice(offset);
+ case 'view':
+ return data.buffer.slice(offset);
+ }
+ };
+ // Convert an ArrayBuffer into its hexadecimal string representation.
+ var hex = function (arrayBuffer) {
+ var i, x, hex_tab = '0123456789abcdef', res = [], binarray = new Uint8Array(arrayBuffer);
+ for (i = 0; i < binarray.length; i++) {
+ x = binarray[i];
+ res[i] = hex_tab.charAt(x >> 4 & 15) + hex_tab.charAt(x >> 0 & 15);
+ }
+ return res.join('');
+ };
+ var ceilHeapSize = function (v) {
+ // The asm.js spec says:
+ // The heap object's byteLength must be either
+ // 2^n for n in [12, 24) or 2^24 * n for n ≥ 1.
+ // Also, byteLengths smaller than 2^16 are deprecated.
+ var p;
+ // If v is smaller than 2^16, the smallest possible solution
+ // is 2^16.
+ if (v <= 65536)
+ return 65536;
+ // If v < 2^24, we round up to 2^n,
+ // otherwise we round up to 2^24 * n.
+ if (v < 16777216) {
+ for (p = 1; p < v; p = p << 1);
+ } else {
+ for (p = 16777216; p < v; p += 16777216);
+ }
+ return p;
+ };
+ // Initialize the internal data structures to a new capacity.
+ var init = function (size) {
+ if (size % 64 > 0) {
+ throw new Error('Chunk size must be a multiple of 128 bit');
+ }
+ self$2.maxChunkLen = size;
+ self$2.padMaxChunkLen = padlen(size);
+ // The size of the heap is the sum of:
+ // 1. The padded input message size
+ // 2. The extended space the algorithm needs (320 byte)
+ // 3. The 160 bit state the algoritm uses
+ self$2.heap = new ArrayBuffer(ceilHeapSize(self$2.padMaxChunkLen + 320 + 20));
+ self$2.h32 = new Int32Array(self$2.heap);
+ self$2.h8 = new Int8Array(self$2.heap);
+ self$2.core = RushaCore({
+ Int32Array: Int32Array,
+ DataView: DataView
+ }, {}, self$2.heap);
+ self$2.buffer = null;
+ };
+ // Iinitializethe datastructures according
+ // to a chunk siyze.
+ init(chunkSize || 64 * 1024);
+ var initState = function (heap, padMsgLen) {
+ var io = new Int32Array(heap, padMsgLen + 320, 5);
+ io[0] = 1732584193;
+ io[1] = -271733879;
+ io[2] = -1732584194;
+ io[3] = 271733878;
+ io[4] = -1009589776;
+ };
+ var padChunk = function (chunkLen, msgLen) {
+ var padChunkLen = padlen(chunkLen);
+ var view = new Int32Array(self$2.heap, 0, padChunkLen >> 2);
+ padZeroes(view, chunkLen);
+ padData(view, chunkLen, msgLen);
+ return padChunkLen;
+ };
+ // Write data to the heap.
+ var write = function (data, chunkOffset, chunkLen) {
+ convFn(data)(self$2.h8, self$2.h32, chunkOffset, chunkLen, 0);
+ };
+ // Initialize and call the RushaCore,
+ // assuming an input buffer of length len * 4.
+ var coreCall = function (data, chunkOffset, chunkLen, msgLen, finalize) {
+ var padChunkLen = chunkLen;
+ if (finalize) {
+ padChunkLen = padChunk(chunkLen, msgLen);
+ }
+ write(data, chunkOffset, chunkLen);
+ self$2.core.hash(padChunkLen, self$2.padMaxChunkLen);
+ };
+ var getRawDigest = function (heap, padMaxChunkLen) {
+ var io = new Int32Array(heap, padMaxChunkLen + 320, 5);
+ var out = new Int32Array(5);
+ var arr = new DataView(out.buffer);
+ arr.setInt32(0, io[0], false);
+ arr.setInt32(4, io[1], false);
+ arr.setInt32(8, io[2], false);
+ arr.setInt32(12, io[3], false);
+ arr.setInt32(16, io[4], false);
+ return out;
+ };
+ // Calculate the hash digest as an array of 5 32bit integers.
+ var rawDigest = this.rawDigest = function (str) {
+ var msgLen = str.byteLength || str.length;
+ initState(self$2.heap, self$2.padMaxChunkLen);
+ var chunkOffset = 0, chunkLen = self$2.maxChunkLen, last;
+ for (chunkOffset = 0; msgLen > chunkOffset + chunkLen; chunkOffset += chunkLen) {
+ coreCall(str, chunkOffset, chunkLen, msgLen, false);
+ }
+ coreCall(str, chunkOffset, msgLen - chunkOffset, msgLen, true);
+ return getRawDigest(self$2.heap, self$2.padMaxChunkLen);
+ };
+ // The digest and digestFrom* interface returns the hash digest
+ // as a hex string.
+ this.digest = this.digestFromString = this.digestFromBuffer = this.digestFromArrayBuffer = function (str) {
+ return hex(rawDigest(str).buffer);
+ };
+ }
+ ;
+ // The low-level RushCore module provides the heart of Rusha,
+ // a high-speed sha1 implementation working on an Int32Array heap.
+ // At first glance, the implementation seems complicated, however
+ // with the SHA1 spec at hand, it is obvious this almost a textbook
+ // implementation that has a few functions hand-inlined and a few loops
+ // hand-unrolled.
+ function RushaCore(stdlib, foreign, heap) {
+ 'use asm';
+ var H = new stdlib.Int32Array(heap);
+ function hash(k, x) {
+ // k in bytes
+ k = k | 0;
+ x = x | 0;
+ 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;
+ y0 = H[x + 320 >> 2] | 0;
+ y1 = H[x + 324 >> 2] | 0;
+ y2 = H[x + 328 >> 2] | 0;
+ y3 = H[x + 332 >> 2] | 0;
+ y4 = H[x + 336 >> 2] | 0;
+ for (i = 0; (i | 0) < (k | 0); i = i + 64 | 0) {
+ z0 = y0;
+ z1 = y1;
+ z2 = y2;
+ z3 = y3;
+ z4 = y4;
+ for (j = 0; (j | 0) < 64; j = j + 4 | 0) {
+ t1 = H[i + j >> 2] | 0;
+ t0 = ((y0 << 5 | y0 >>> 27) + (y1 & y2 | ~y1 & y3) | 0) + ((t1 + y4 | 0) + 1518500249 | 0) | 0;
+ y4 = y3;
+ y3 = y2;
+ y2 = y1 << 30 | y1 >>> 2;
+ y1 = y0;
+ y0 = t0;
+ ;
+ H[k + j >> 2] = t1;
+ }
+ for (j = k + 64 | 0; (j | 0) < (k + 80 | 0); j = j + 4 | 0) {
+ 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;
+ t0 = ((y0 << 5 | y0 >>> 27) + (y1 & y2 | ~y1 & y3) | 0) + ((t1 + y4 | 0) + 1518500249 | 0) | 0;
+ y4 = y3;
+ y3 = y2;
+ y2 = y1 << 30 | y1 >>> 2;
+ y1 = y0;
+ y0 = t0;
+ ;
+ H[j >> 2] = t1;
+ }
+ for (j = k + 80 | 0; (j | 0) < (k + 160 | 0); j = j + 4 | 0) {
+ 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;
+ t0 = ((y0 << 5 | y0 >>> 27) + (y1 ^ y2 ^ y3) | 0) + ((t1 + y4 | 0) + 1859775393 | 0) | 0;
+ y4 = y3;
+ y3 = y2;
+ y2 = y1 << 30 | y1 >>> 2;
+ y1 = y0;
+ y0 = t0;
+ ;
+ H[j >> 2] = t1;
+ }
+ for (j = k + 160 | 0; (j | 0) < (k + 240 | 0); j = j + 4 | 0) {
+ 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;
+ t0 = ((y0 << 5 | y0 >>> 27) + (y1 & y2 | y1 & y3 | y2 & y3) | 0) + ((t1 + y4 | 0) - 1894007588 | 0) | 0;
+ y4 = y3;
+ y3 = y2;
+ y2 = y1 << 30 | y1 >>> 2;
+ y1 = y0;
+ y0 = t0;
+ ;
+ H[j >> 2] = t1;
+ }
+ for (j = k + 240 | 0; (j | 0) < (k + 320 | 0); j = j + 4 | 0) {
+ 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;
+ t0 = ((y0 << 5 | y0 >>> 27) + (y1 ^ y2 ^ y3) | 0) + ((t1 + y4 | 0) - 899497514 | 0) | 0;
+ y4 = y3;
+ y3 = y2;
+ y2 = y1 << 30 | y1 >>> 2;
+ y1 = y0;
+ y0 = t0;
+ ;
+ H[j >> 2] = t1;
+ }
+ y0 = y0 + z0 | 0;
+ y1 = y1 + z1 | 0;
+ y2 = y2 + z2 | 0;
+ y3 = y3 + z3 | 0;
+ y4 = y4 + z4 | 0;
+ }
+ H[x + 320 >> 2] = y0;
+ H[x + 324 >> 2] = y1;
+ H[x + 328 >> 2] = y2;
+ H[x + 332 >> 2] = y3;
+ H[x + 336 >> 2] = y4;
+ }
+ return { hash: hash };
+ }
+}(this));
diff --git a/app/webogram.appcache b/app/webogram.appcache
index f32aa44a..8cf21886 100644
--- a/app/webogram.appcache
+++ b/app/webogram.appcache
@@ -1,6 +1,6 @@
CACHE MANIFEST
-# 39
+# 40
NETWORK:
*