I need to convert strings to some form of hash. Is this possible in JavaScript?
I\'m not utilizing a server-side language so I can\'t do it that way.
This should be a bit more secure hash than some other answers, but in a function, without any preloaded source
I created basicly a minified simplified version of sha1.
You take the bytes of the string and group them by 4 to 32bit "words"
Then we extend every 8 words to 40 words (for bigger impact on the result).
This goes to the hashing function (the last reduce) where we do some maths with the current state and the input. We always get 4 words out.
This is almost a one-command/one-line version using map,reduce... instead of loops, but it is still pretty fast
String.prototype.hash = function(){
var rot = (word, shift) => word << shift | word >>> (32 - shift);
return unescape(encodeURIComponent(this.valueOf())).split("").map(char =>
char.charCodeAt(0)
).reduce((done, byte, idx, arr) =>
idx % 4 == 0 ? [...done, arr.slice(idx, idx + 4)] : done
, []).reduce((done, group) =>
[...done, group[0] << 24 | group[1] << 16 | group[2] << 8 | group[3]]
, []).reduce((done, word, idx, arr) =>
idx % 8 == 0 ? [...done, arr.slice(idx, idx + 8)] : done
, []).map(group => {
while(group.length < 40)
group.push(rot(group[group.length - 2] ^ group[group.length - 5] ^ group[group.length - 8], 3));
return group;
}).flat().reduce((state, word, idx, arr) => {
var temp = ((state[0] + rot(state[1], 5) + word + idx + state[3]) & 0xffffffff) ^ state[idx % 2 == 0 ? 4 : 5](state[0], state[1], state[2]);
state[0] = rot(state[1] ^ state[2], 11);
state[1] = ~state[2] ^ rot(~state[3], 19);
state[2] = rot(~state[3], 11);
state[3] = temp;
return state;
}, [0xbd173622, 0x96d8975c, 0x3a6d1a23, 0xe5843775,
(w1, w2, w3) => (w1 & rot(w2, 5)) | (~rot(w1, 11) & w3),
(w1, w2, w3) => w1 ^ rot(w2, 5) ^ rot(w3, 11)]
).slice(0, 4).map(p =>
p >>> 0
).map(word =>
("0000000" + word.toString(16)).slice(-8)
).join("");
};
we also convert the output to hex to get a string instead of word array.
Usage is simple. for expample "a string".hash() will return "88a09e8f9cc6f8c71c4497fbb36f84cd"
String.prototype.hash = function(){
var rot = (word, shift) => word << shift | word >>> (32 - shift);
return unescape(encodeURIComponent(this.valueOf())).split("").map(char =>
char.charCodeAt(0)
).reduce((done, byte, idx, arr) =>
idx % 4 == 0 ? [...done, arr.slice(idx, idx + 4)] : done
, []).reduce((done, group) =>
[...done, group[0] << 24 | group[1] << 16 | group[2] << 8 | group[3]]
, []).reduce((done, word, idx, arr) =>
idx % 8 == 0 ? [...done, arr.slice(idx, idx + 8)] : done
, []).map(group => {
while(group.length < 40)
group.push(rot(group[group.length - 2] ^ group[group.length - 5] ^ group[group.length - 8], 3));
return group;
}).flat().reduce((state, word, idx, arr) => {
var temp = ((state[0] + rot(state[1], 5) + word + idx + state[3]) & 0xffffffff) ^ state[idx % 2 == 0 ? 4 : 5](state[0], state[1], state[2]);
state[0] = rot(state[1] ^ state[2], 11);
state[1] = ~state[2] ^ rot(~state[3], 19);
state[2] = rot(~state[3], 11);
state[3] = temp;
return state;
}, [0xbd173622, 0x96d8975c, 0x3a6d1a23, 0xe5843775,
(w1, w2, w3) => (w1 & rot(w2, 5)) | (~rot(w1, 11) & w3),
(w1, w2, w3) => w1 ^ rot(w2, 5) ^ rot(w3, 11)]
).slice(0, 4).map(p =>
p >>> 0
).map(word =>
("0000000" + word.toString(16)).slice(-8)
).join("");
};
let str = "the string could even by empty";
console.log(str.hash())//9f9aeca899367572b875b51be0d566b5