275 lines
7.0 KiB
JavaScript
275 lines
7.0 KiB
JavaScript
;(function() {
|
|
|
|
var util = {};
|
|
util.low = function(byte) {
|
|
return byte & 0xf;
|
|
};
|
|
|
|
|
|
util.high = function(byte) {
|
|
return byte >>> 4 & 0xf;
|
|
};
|
|
|
|
util.madd = function(a, b) { // TODO: rename to madd256
|
|
return (a + b) % N;
|
|
// return (a + b) & 0xff; // when N = 256, 0xff = N - 1
|
|
};
|
|
|
|
|
|
util.msub = function(a, b) {// TODO: rename to msub256
|
|
return util.madd(N, a - b);
|
|
};
|
|
|
|
util.swap = function(lst, p1, p2) {
|
|
var tmp = lst[p1];
|
|
lst[p1] = lst[p2];
|
|
lst[p2] = tmp;
|
|
};
|
|
|
|
util.gcd = function(a, b){
|
|
var t;
|
|
while (b !== 0) {
|
|
t = b;
|
|
b = a % b;
|
|
a = t;
|
|
}
|
|
return a;
|
|
};
|
|
|
|
var N = 256;
|
|
var N_OVER_TWO_FLOOR = Math.floor(N / 2);
|
|
var TWO_N = 2 * N;
|
|
|
|
var spritz = {};
|
|
|
|
spritz._util = util;
|
|
|
|
spritz._initializeState = function _initializeState() {
|
|
var state = {};
|
|
|
|
state.i = 0;
|
|
state.j = 0;
|
|
state.k = 0;
|
|
state.z = 0;
|
|
state.a = 0;
|
|
state.w = 1;
|
|
|
|
state.S = [];
|
|
for (var i = 0; i < N; i++) {
|
|
state.S[i] = i;
|
|
}
|
|
return state;
|
|
};
|
|
|
|
spritz._absorb = function _absorb(I, state){
|
|
var v;
|
|
/*
|
|
basic validation of I
|
|
consider bounds-checking and deep-checking of each N-value such that they are in the valid range (0 <= x < N)
|
|
*/
|
|
if(!(Array.isArray(I) && I.length > 0)){
|
|
return false;
|
|
}
|
|
|
|
for(v = 0; v < I.length; v++){
|
|
spritz._absorbByte(I[v], state);
|
|
}
|
|
return true;
|
|
};
|
|
|
|
spritz._absorbByte = function _absorbByte(b, state) {
|
|
spritz._absorbNibble(util.low(b), state);
|
|
spritz._absorbNibble(util.high(b), state);
|
|
};
|
|
|
|
spritz._absorbNibble = function _absorbNibble(x, state) {
|
|
if (state.a === N_OVER_TWO_FLOOR){
|
|
spritz.shuffle(state);
|
|
}
|
|
|
|
util.swap(state.S, state.a, util.madd(N_OVER_TWO_FLOOR, x));
|
|
state.a = util.madd(state.a, 1);
|
|
};
|
|
|
|
spritz._absorbStop = function _absorbStop(state){
|
|
if(state.a === N_OVER_TWO_FLOOR){
|
|
spritz._shuffle(state);
|
|
}
|
|
state.a = util.madd(state.a, 1);
|
|
};
|
|
|
|
spritz._shuffle = function _shuffle(state){
|
|
spritz._whip(TWO_N, state);
|
|
spritz._crush(state);
|
|
spritz._whip(TWO_N, state);
|
|
spritz._crush(state);
|
|
spritz._whip(TWO_N, state);
|
|
state.a = 0;
|
|
};
|
|
|
|
spritz._whip = function _whip(r, state) {
|
|
for (var i = 0; i < r; i++) {
|
|
spritz._update(state);
|
|
}
|
|
do {
|
|
state.w = util.madd(state.w, 1);
|
|
} while (util.gcd(state.w, N) !== 1);
|
|
// NB. a simple-case assumption is that if N is a power of 2 then one could instead use:
|
|
// w = madd(w, 2);
|
|
};
|
|
|
|
spritz._crush = function _crush(state) {
|
|
var index;
|
|
for (var i = 0; i < N_OVER_TWO_FLOOR; i++) {
|
|
index = N - i - 1;
|
|
if (state.S[i] > state.S[index]) {
|
|
util.swap(state.S, i, index);
|
|
}
|
|
}
|
|
};
|
|
|
|
spritz._update = function _update(state) { //done
|
|
state.i = util.madd(state.i, state.w);
|
|
state.j = util.madd(state.k, state.S[util.madd(state.j, state.S[state.i])]);
|
|
state.k = util.madd(state.i + state.k, state.S[state.j]);
|
|
util.swap(state.S, state.i, state.j);
|
|
};
|
|
|
|
spritz._squeeze = function _squeeze(r, state) {
|
|
if (state.a > 0) {
|
|
spritz._shuffle(state);
|
|
}
|
|
|
|
var P = [];
|
|
for (var i = 0; i < r; i++) {
|
|
P[i] = spritz._drip(state);
|
|
}
|
|
return P;
|
|
};
|
|
|
|
spritz._drip = function _drip(state){
|
|
if (state.a > 0) {
|
|
spritz._shuffle(state);
|
|
}
|
|
spritz._update(state);
|
|
return spritz._output(state);
|
|
};
|
|
|
|
spritz._output = function _output(state) {
|
|
var idx = util.madd(state.z, state.k);
|
|
idx = util.madd(state.i, state.S[idx]);
|
|
idx = util.madd(state.j, state.S[idx]);
|
|
state.z = state.S[idx];
|
|
return state.z;
|
|
};
|
|
|
|
spritz._keySetup = function _keySetup(K) {
|
|
var state = spritz._initializeState();
|
|
spritz._absorb(K, state);
|
|
return state;
|
|
};
|
|
|
|
spritz.stringToUtf8ByteArray = function stringToUtf8ByteArray(utf8Array){
|
|
var utf8 = unescape(encodeURIComponent(utf8Array));
|
|
|
|
var arr = [];
|
|
for (var i = 0; i < utf8.length; i++) {
|
|
arr.push(utf8.charCodeAt(i));
|
|
}
|
|
return arr;
|
|
};
|
|
|
|
spritz.utf8ByteArrayToString = function utf8ByteArrayToString(utf8Array){
|
|
var ret = "";
|
|
for(var i = 0; i < utf8Array.length; i++){
|
|
ret += String.fromCharCode(utf8Array[i]);
|
|
}
|
|
return decodeURIComponent(escape(ret));
|
|
};
|
|
|
|
spritz.hash = function hash(M, r){
|
|
if(typeof M == 'string'){
|
|
return spritz.hash(spritz.stringToUtf8ByteArray(M), r);
|
|
}
|
|
var state = spritz._initializeState();
|
|
spritz._absorb(M, state);
|
|
spritz._absorbStop(state);
|
|
spritz._absorb([r & 0xff], state); // NB. restricted(!) to 255-byte hashes
|
|
return spritz._squeeze(r, state);
|
|
};
|
|
|
|
spritz.encrypt = function encrypt(K, M) {
|
|
|
|
var C = [], stream , i;
|
|
|
|
var state = spritz._keySetup(K);
|
|
stream = spritz._squeeze(M.length, state);
|
|
for (i = 0; i < M.length; i++) {
|
|
C[i] = util.madd(M[i], stream[i]);
|
|
}
|
|
return C;
|
|
};
|
|
|
|
spritz.decrypt = function decrypt(K, C) {
|
|
var M = [] , stream , i;
|
|
var state = spritz._keySetup(K);
|
|
stream = spritz._squeeze(C.length, state);
|
|
for (i = 0; i < C.length; i++) {
|
|
M[i] = util.msub(C[i], stream[i]);
|
|
}
|
|
return M;
|
|
};
|
|
|
|
// Export spritz as lodash 4.5.0.
|
|
|
|
var objectTypes = {
|
|
'function': true,
|
|
'object': true
|
|
};
|
|
|
|
function checkGlobal(value) {
|
|
return (value && value.Object === Object) ? value : null;
|
|
}
|
|
|
|
var freeWindow = checkGlobal(objectTypes[typeof window] && window);
|
|
var freeSelf = checkGlobal(objectTypes[typeof self] && self);
|
|
var freeGlobal = checkGlobal(freeExports && freeModule && typeof global == 'object' && global);
|
|
var freeModule = (objectTypes[typeof module] && module && !module.nodeType) ? module : undefined;
|
|
var freeExports = (objectTypes[typeof exports] && exports && !exports.nodeType) ? exports : undefined;
|
|
var moduleExports = (freeModule && freeModule.exports === freeExports) ? freeExports: undefined;
|
|
var thisGlobal = checkGlobal(objectTypes[typeof this] && this);
|
|
|
|
|
|
var root = freeGlobal || ((freeWindow !== (thisGlobal && thisGlobal.window)) && freeWindow) || freeSelf || thisGlobal || Function('return this')();
|
|
|
|
|
|
// Expose lodash on the free variable `window` or `self` when available. This
|
|
// prevents errors in cases where lodash is loaded by a script tag in the presence
|
|
// of an AMD loader. See http://requirejs.org/docs/errors.html#mismatch for more details.
|
|
(freeWindow || freeSelf || {}).spritz = spritz;
|
|
|
|
// Some AMD build optimizers like r.js check for condition patterns like the following:
|
|
if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
|
|
// Define as an anonymous module so, through path mapping, it can be
|
|
// referenced as the "underscore" module.
|
|
define(function() {
|
|
return spritz;
|
|
});
|
|
}
|
|
// Check for `exports` after `define` in case a build optimizer adds an `exports` object.
|
|
else if (freeExports && freeModule) {
|
|
// Export for Node.js.
|
|
if (moduleExports) {
|
|
freeModule.exports = spritz;
|
|
}
|
|
// Export for CommonJS support.
|
|
freeExports.spritz = spritz;
|
|
}
|
|
else {
|
|
// Export to the global object.
|
|
root.spritz = spritz;
|
|
}
|
|
|
|
|
|
}.call(this)); // close the prefix
|