feature(edit) rm client sha

This commit is contained in:
coderaiser 2013-11-21 11:11:26 +00:00
parent c94515d0a2
commit 1b47867f9c
5 changed files with 18 additions and 389 deletions

View file

@ -1781,30 +1781,24 @@ var CloudCmd, Util, DOM, CloudFunc, Dialog;
* @param data
* @param callback
*/
this.saveDataToStorage = function(name, data, hash, callback) {
this.saveDataToStorage = function(name, data, callback) {
CloudCmd.getConfig(function(config) {
var allowed = config.localStorage,
isDir = DOM.isCurrentIsDir(),
nameHash = name + '-hash',
nameData = name + '-data',
save = function(hash) {
Storage.set(nameHash, hash);
Storage.set(nameData, data);
};
nameData = name + '-data';
if (!allowed || isDir)
Util.exec(callback);
else {
if (hash)
save(hash);
else
DOM.checkStorageHash(name, function(error, equal, hash) {
if (!error && !equal)
save(hash);
Util.exec(callback, hash);
});
}
else
DOM.checkStorageHash(name, function(error, equal, hash) {
if (!error && !equal) {
Storage.set(nameHash, hash);
Storage.set(nameData, data);
}
Util.exec(callback, hash);
});
});
};

View file

@ -12,7 +12,6 @@ var CloudCmd, Util, DOM, CloudFunc, ace, DiffProto, diff_match_patch;
Value,
Edit = this,
Diff,
SHA,
Ace,
Msg,
Dialog = DOM.Dialog,
@ -161,20 +160,12 @@ var CloudCmd, Util, DOM, CloudFunc, ace, DiffProto, diff_match_patch;
}
DOM.checkStorageHash(lPath, function(error, equal) {
var ret,
msg = 'File is changed, overwrite?',
saveFunc = function(text) {
var hash = SHA.digest(Value);
onSave(text, hash);
};
if (!error && !equal)
ret = Dialog.confirm(msg);
else
DOM.RESTful.save(lPath, lValue, saveFunc, query);
if (!error) {
if (!equal)
query = '';
if (ret)
DOM.RESTful.save(lPath, lValue, saveFunc);
DOM.RESTful.save(lPath, lValue, onSave, query);
}
});
}, function(callback) {
@ -188,16 +179,12 @@ var CloudCmd, Util, DOM, CloudFunc, ace, DiffProto, diff_match_patch;
function diff(pNewValue, pCallBack) {
var libs = [
LIBDIR + 'diff.js',
LIBDIR + 'diff/diff-match-patch.js',
LIBDIR + 'sha1/rusha.js'
LIBDIR + 'diff/diff-match-patch.js'
];
DOM.anyLoadInParallel(libs, function() {
var patch;
if (!SHA)
SHA = new Rusha();
if (!Diff)
Diff = new DiffProto(diff_match_patch);
@ -243,7 +230,7 @@ var CloudCmd, Util, DOM, CloudFunc, ace, DiffProto, diff_match_patch;
if (!isError) {
Edit.showMessage(text);
DOM.saveDataToStorage(path, Value, hash);
DOM.saveDataToStorage(path, Value);
} else {
ret = Dialog.confirm(text + msg);

View file

@ -1,60 +0,0 @@
# Rusha
*A high-performance pure-javascript SHA1 implementation suitable for large binary data.*
## Prologue: The Sad State of Javascript SHA1 implementations
When we started experimenting with alternative upload technologies at [doctape](http://doctape.com) that required creating SHA1 hashes of the data locally on the client, it quickly became obvious that there were no performant pure-js implementations of SHA1 that worked correctly on binary data.
Jeff Mott's [CryptoJS](http://code.google.com/p/crypto-js/) and Brian Turek's [jsSHA](http://caligatio.github.com/jsSHA/) were both hash functions that worked correctly on ASCII strings of a small size, but didn't scale to large data and/or didn't work correctly with binary data.
(On a sidenode, as of now Tim Caswell's [Cifre](http://github.com/openpeer/cifre) actually works with large binary data, as opposed to previously statet.)
By modifying Paul Johnston's [sha1.js](http://pajhome.org.uk/crypt/md5/sha1.html) slightly, it worked correctly on binary data but was unfortunately very slow, especially on V8. So a few days were invested on my side to implement a Johnston-inspired SHA1 hashing function with a heavy focus on performance.
The result of this process is Rusha, a SHA1 hash function that works flawlessly on large amounts binary data, such as binary strings or ArrayBuffers returned by the HTML5 File API, and leverages the soon-to-be-landed-in-firefox [asm.js](http://asmjs.org/spec/latest/) with whose support its within *half of native speed*!
## Installing
### Node.JS
There is really no point in doing this, since Node.JS already has a wonderful `crypto` module that is leveraging low-level hardware instructions to perform really nice. Your can see the comparison below in the benchmarks.
Rusha is available on [npm](http://npmjs.org/) via `npm install rusha`.
If you still want to do this, anyhow, just `require()` the `rusha.js` file, follow the instructions on _Using the Rusha Object_.
### Browser
Rusha is available on [bower](http://twitter.github.com/bower/) via `bower install rusha`.
It is highly recommended to run CPU-intensive tasks in a [Web Worker](http://developer.mozilla.org/en-US/docs/DOM/Using_web_workers). To do so, just start a worker with `var worker = new Worker('rusha.js')` and start sending it jobs. Follow the instructions on _Using the Rusha Worker_.
If you can't, for any reason, use Web Workers, include the `rusha.js` file in a `<script>` tag and follow the instructions on _Using the Rusha Object_.
## Using the Rusha Object
Your instantiate a new Rusha object by doing `var r = new Rusha(optionalSizeHint)`. When created, it provides the following methods:
- `Rusha#digest(d)`: Create a hex digest from data of the three kinds mentioned below, or throw and error if the type is unsupported.
- `Rusha#digestFromString(s)`: Create a hex digest from a binary `String`. A binary string is expected to only contain characters whose charCode < 256.
- `Rusha#digestFromBuffer(b)`: Create a hex digest from a `Buffer` or `Array`. Both are expected to only contain elements < 256.
- `Rusha#digestFromArrayBuffer(a)`: Create a hex digest from an `ArrayBuffer` object.
- `Rusha#rawDigest(d)`: Behaves just like #digest(d), except that it returns the digest as an Int32Array of size 5.
## Using the Rusha Worker
You can send your instance of the web worker messages in the format `{id: jobid, data: dataobject}`. The worker then sends back a message in the format `{id: jobid, hash: hash}`, were jobid is the id of the job previously received and hash is the hash of the data-object you passed, be it a `Blob`, `Array`, `Buffer`, `ArrayBuffer` or `String`.
## Benchmarks
Tested were my Rusha implementation, the sha1.js implementation by [P. A. Johnston](http://pajhome.org.uk/crypt/md5/sha1.html), Tim Caswell's [Cifre](http://github.com/openpeer/cifre) and the Node.JS native implementation.
If you want to check the performance for yourself in your own browser, I compiled a [JSPerf Page](http://jsperf.com/rusha/2).
A normalized estimation based on the best results for each implementation, smaller is better:
![rough performance graph](http://awesam.de/rusha/bench/unscientific01.png)
Results per Implementation and Platform:
![performance chart](https://docs.google.com/spreadsheet/oimg?key=0Ag9CYh5kHpegdDB1ZG16WU1xVFgxdjRuQUVwQXRnWVE&oid=1&zx=pcatr2aits9)
All tests were performed on a MacBook Air 1.7 GHz Intel Core i5 and 4 GB 1333 MHz DDR3.

View file

@ -1,22 +0,0 @@
{
"name": "rusha",
"version": "0.7.2",
"description": "A high-performance pure-javascript SHA1 implementation suitable for large binary data.",
"main": "rusha.js",
"keywords": [
"sha1",
"binary",
"crypto",
"hash"
],
"repository": {
"type": "git",
"url": "https://github.com/srijs/rusha"
},
"devDependencies": {
"jsmin": "~1.0"
},
"author": "Sam Rijs",
"license": "MIT",
"readmeFilename": "README.md"
}

View file

@ -1,270 +0,0 @@
(function () {
// 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 window !== 'undefined') {
window.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});
};
}
// 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 (sizeHint) {
"use strict";
// Private object structure.
var self = {fill: 0};
// Calculate the length of buffer that the sha1 routine uses
// including the padding.
var padlen = function (len) {
return len + 1 + ((len ) % 64 < 56 ? 56 : 56 + 64) - (len ) % 64 + 8;
};
var padZeroes = function (bin, len) {
for (var i = len >> 2; i < bin.length; i++) bin[i] = 0;
};
var padData = function (bin, len) {
bin[len>>2] |= 0x80 << (24 - (len % 4 << 3));
bin[(((len >> 2) + 2) & ~0x0f) + 15] = len << 3;
};
// Convert a binary string to a big-endian Int32Array using
// four characters per slot and pad it per the sha1 spec.
// A binary string is expected to only contain char codes < 256.
var convStr = function (str, bin, len) {
var i;
for (i = 0; i < len; i = i + 4 |0) {
bin[i>>2] = str.charCodeAt(i) << 24 |
str.charCodeAt(i+1) << 16 |
str.charCodeAt(i+2) << 8 |
str.charCodeAt(i+3);
}
};
// Convert a buffer or array to a big-endian Int32Array using
// four elements per slot and pad it per the sha1 spec.
// The buffer or array is expected to only contain elements < 256.
var convBuf = function (buf, bin, len) {
var i, m = len % 4, j = len - m;
for (i = 0; i < j; i = i + 4 |0) {
bin[i>>2] = buf[i] << 24 |
buf[i+1] << 16 |
buf[i+2] << 8 |
buf[i+3];
}
switch (m) {
case 0: bin[j>>2] |= buf[j+3];
case 3: bin[j>>2] |= buf[j+2] << 8;
case 2: bin[j>>2] |= buf[j+1] << 16;
case 1: bin[j>>2] |= buf[j] << 24;
}
};
// Convert general data to a big-endian Int32Array written on the
// heap and return it's length;
var conv = function (data, bin, len) {
if (typeof data === 'string') {
return convStr(data, bin, len);
} else if (data instanceof Array || (typeof global !== 'undefined' &&
typeof global.Buffer !== 'undefined' &&
data instanceof global.Buffer)) {
return convBuf(data, bin, len);
} else if (data instanceof ArrayBuffer) {
return convBuf(new Uint8Array(data), bin, len);
} else if (data.buffer instanceof ArrayBuffer) {
return convBuf(new Uint8Array(data.buffer), bin, len);
} else {
throw new Error('Unsupported data type.');
}
};
// Convert a array containing 32 bit integers
// into its hexadecimal string representation.
var hex = function (binarray) {
var i, x, hex_tab = "0123456789abcdef", res = [];
for (i = 0; i < binarray.length; i++) {
x = binarray[i];
res[i] = hex_tab.charAt((x >> 28) & 0xF) +
hex_tab.charAt((x >> 24) & 0xF) +
hex_tab.charAt((x >> 20) & 0xF) +
hex_tab.charAt((x >> 16) & 0xF) +
hex_tab.charAt((x >> 12) & 0xF) +
hex_tab.charAt((x >> 8) & 0xF) +
hex_tab.charAt((x >> 4) & 0xF) +
hex_tab.charAt((x >> 0) & 0xF);
}
return res.join('');
};
var nextPow2 = function (v) {
var p = 1; while (p < v) p = p << 1; return p;
};
// Resize the internal data structures to a new capacity.
var resize = function (size) {
self.sizeHint = size;
self.heap = new ArrayBuffer(nextPow2(padlen(size) + 320));
self.core = RushaCore({Int32Array: Int32Array}, {}, self.heap);
};
// On initialize, resize the datastructures according
// to an optional size hint.
resize(sizeHint || 0);
// Initialize and call the RushaCore,
// assuming an input buffer of length len * 4.
var coreCall = function (len) {
var h = new Int32Array(self.heap, len << 2, 5);
h[0] = 1732584193;
h[1] = -271733879;
h[2] = -1732584194;
h[3] = 271733878;
h[4] = -1009589776;
self.core.hash(len);
};
// Calculate the hash digest as an array of 5 32bit integers.
var rawDigest = this.rawDigest = function (str) {
var len = str.byteLength || str.length;
if (len > self.sizeHint) {
resize(len);
}
var view = new Int32Array(self.heap, 0, padlen(len) >> 2);
padZeroes(view, len);
conv(str, view, len);
padData(view, len);
coreCall(view.length);
return new Int32Array(self.heap, 0, 5);
};
// 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));
};
};
// 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) {
k = k|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[k+0<<2>>2]|0;
y1 = H[k+1<<2>>2]|0;
y2 = H[k+2<<2>>2]|0;
y3 = H[k+3<<2>>2]|0;
y4 = H[k+4<<2>>2]|0;
for (i = 0; (i|0) < (k|0); i = i + 16 |0) {
z0 = y0;
z1 = y1;
z2 = y2;
z3 = y3;
z4 = y4;
for (j = 0; (j|0) < 16; j = j + 1 |0) {
t1 = H[i+j<<2>>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>>2] = t1;
}
for (j = k + 16 |0; (j|0) < (k + 20 |0); j = j + 1 |0) {
t1 = (((H[j-3<<2>>2] ^ H[j-8<<2>>2] ^ H[j-14<<2>>2] ^ H[j-16<<2>>2]) << 1 | (H[j-3<<2>>2] ^ H[j-8<<2>>2] ^ H[j-14<<2>>2] ^ H[j-16<<2>>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>>2] = t1;
}
for (j = k + 20 |0; (j|0) < (k + 40 |0); j = j + 1 |0) {
t1 = (((H[j-3<<2>>2] ^ H[j-8<<2>>2] ^ H[j-14<<2>>2] ^ H[j-16<<2>>2]) << 1 | (H[j-3<<2>>2] ^ H[j-8<<2>>2] ^ H[j-14<<2>>2] ^ H[j-16<<2>>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>>2] = t1;
}
for (j = k + 40 |0; (j|0) < (k + 60 |0); j = j + 1 |0) {
t1 = (((H[j-3<<2>>2] ^ H[j-8<<2>>2] ^ H[j-14<<2>>2] ^ H[j-16<<2>>2]) << 1 | (H[j-3<<2>>2] ^ H[j-8<<2>>2] ^ H[j-14<<2>>2] ^ H[j-16<<2>>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>>2] = t1;
}
for (j = k + 60 |0; (j|0) < (k + 80 |0); j = j + 1 |0) {
t1 = (((H[j-3<<2>>2] ^ H[j-8<<2>>2] ^ H[j-14<<2>>2] ^ H[j-16<<2>>2]) << 1 | (H[j-3<<2>>2] ^ H[j-8<<2>>2] ^ H[j-14<<2>>2] ^ H[j-16<<2>>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>>2] = t1;
}
y0 = y0 + z0 |0;
y1 = y1 + z1 |0;
y2 = y2 + z2 |0;
y3 = y3 + z3 |0;
y4 = y4 + z4 |0;
}
H[0] = y0;
H[1] = y1;
H[2] = y2;
H[3] = y3;
H[4] = y4;
}
return {hash: hash};
}
})();