194

Possible Duplicate:
Generate a Hash from string in Javascript/jQuery

Can anyone suggest a simple (i.e. tens of lines of code, not hundreds of lines) hash function written in (browser-compatible) JavaScript? Ideally I'd like something that, when passed a string as input, produces something similar to the 32 character hexadecimal string that's the typical output of MD5, SHA1, etc. It doesn't have to be cryptographically secure, just reasonably resistant to collisions. (My initial use case is URLs, but I'll probably want to use it on other strings in the future.)

Community
  • 1
  • 1
mjs
  • 63,493
  • 27
  • 91
  • 122
  • Is there a particular reason you don't want to use sha1? there are a plethora of examples of this in js – Alex K. May 25 '11 at 10:05
  • 4
    I want to package this with some other code that's about 50 lines long; I don't want my hash function to be 10x as long as the "interesting" bits. – mjs May 25 '11 at 10:28
  • I think I understand your point now. Is there a reason you cannot use an include? Do you really need to use only one file? – jsalonen May 25 '11 at 10:32
  • 5
    Yes I could, and I'm prepared to do that if necessary, but I'd preferably like something self-contained that I can post as a gist on github or similar. – mjs May 25 '11 at 10:44
  • I am looking to create a html page with as many examples of hashing algorythms that I possible can find. Were could I get a list of hashing functions. –  Jul 12 '14 at 22:18
  • 6
    An implementation of [Jenkins's one-at-a-time hash](http://en.wikipedia.org/wiki/Jenkins_hash_function) `window.hashJoaat=function(b){for(var a=0,c=b.length;c--;)a+=b.charCodeAt(c),a+=a<<10,a^=a>>6;a+=a<<3;a^=a>>11;return((a+(a<<15)&4294967295)>>>0).toString(16)};` – Orwellophile Oct 15 '16 at 15:59
  • The [stringHash32() function from AMP](https://github.com/ampproject/amphtml/blob/371a072ed4986410b3671469f603e88721890bad/src/string.js#L121-L129) is likely to be sufficient. – mjs Nov 04 '17 at 23:18

5 Answers5

211

I didn't verify this myself, but you can look at this JavaScript implementation of Java's String.hashCode() method. Seems reasonably short.

With this prototype you can simply call .hashCode() on any string, e.g. "some string".hashCode(), and receive a numerical hash code (more specifically, a Java equivalent) such as 1395333309.

String.prototype.hashCode = function() {
    var hash = 0;
    for (var i = 0; i < this.length; i++) {
        var char = this.charCodeAt(i);
        hash = ((hash<<5)-hash)+char;
        hash = hash & hash; // Convert to 32bit integer
    }
    return hash;
}

2022 EDIT:

It has been long accepted that modifying built-in prototypes is bad practice, so instead you should use a plain function:

/**
 * Returns a hash code from a string
 * @param  {String} str The string to hash.
 * @return {Number}    A 32bit integer
 * @see http://werxltd.com/wp/2010/05/13/javascript-implementation-of-javas-string-hashcode-method/
 */
function hashCode(str) {
    let hash = 0;
    for (let i = 0, len = str.length; i < len; i++) {
        let chr = str.charCodeAt(i);
        hash = (hash << 5) - hash + chr;
        hash |= 0; // Convert to 32bit integer
    }
    return hash;
}
Vitim.us
  • 20,746
  • 15
  • 92
  • 109
Barak
  • 2,416
  • 2
  • 15
  • 10
  • 13
    SHA1 and MD5 are ridiculously slow. I did a bunch of comparison tests, and this implementation of Java's hash proved fastest, and as few collisions (on relatively uniform data) as any of the others I tried. Very short and sweet. – Jimbly May 31 '12 at 05:55
  • 41
    Really cool! Only thing is this pollutes the `prototype` of `String` with a non-Ecmascript method. I would rewrite it as a stand-alone function, maybe put it in your util library. – Husky Oct 16 '12 at 09:37
  • 7
    Another thing is that it creates a global variable `i`, because he forgot the `var` keyword in the loop. But those issues can easily be fixed. – Stijn de Witt Mar 03 '16 at 08:48
  • @Jimbly Thanks for testing it and reporting back the results. Very helpful! – Stijn de Witt Mar 03 '16 at 08:49
  • Is Javascript's implementation written in stone? Are there any guarantees that they will not modify it with future versions of Javascript? What happens if they do decide to "improve" their algorithm? That would probably result in strings being hashed to new values making those values incompatible with any values you stored or where you rely upon a consistent hash value. I would be very leary about using a blackbox api where you have no control of the source code. – Johann Jul 29 '17 at 19:23
  • 2
    Documentation for Java's `String.hashCode()`, since the link in the article has 404'd: http://devdocs.io/openjdk~8/java/lang/string#hashCode-- – waldyrious Aug 16 '17 at 08:59
  • there's a more popular question in SO with the same answer https://stackoverflow.com/questions/7616461/generate-a-hash-from-string-in-javascript-jquery – JLarky May 05 '18 at 03:22
  • 24
    Micro-optimization: remove the `if (this.length == 0) {return hash}` block since it's redundant anyway (the `for` is executed while length is positive, otherwise 0 is returned by default). Do I miss something? – Eugen Mihailescu Apr 19 '19 at 05:41
  • 2
    Since we are writing javascript differently at 2019, here is the same thing, but without binding it to the String prototype... ``` function hashCode(source) { let hash = 0; if (source.length == 0) { return hash; } for (var i = 0; i < source.length; i++) { var char = source.charCodeAt(i); hash = ((hash<<5)-hash)+char; hash = hash & hash; // Convert to 32bit integer } return hash; } ``` – Liron Navon May 07 '19 at 10:43
  • 14
    In one line: `Array.from(str).reduce((hash, char) => 0 | (31 * hash + char.charCodeAt(0)), 0)` (where `str` is the string) – Mingwei Samuel Jul 13 '20 at 08:58
  • But how can we undo it? – Cybernetic Mar 03 '21 at 18:18
  • 2
    @Cybernetic, hashing is a one-way technique that is not reversible and cannot be undone – Mouneer Mar 26 '21 at 15:49
  • @Mouneer In general yes, but it is reversible for the owner of the key. Thus there should be a way for a key holder to reverse the operation. For example, if you were using this to hash a password on a server. – Cybernetic Mar 26 '21 at 15:54
  • 1
    @Cybernetic, this is how people use them with passwords for example but this cannot be called "Undo" as it means that you can get back the original hashed string and this is basically not applicable – Mouneer Mar 26 '21 at 17:19
  • 2
    One collision of this algo: *FB* & *Ea* – Shub May 18 '21 at 16:42
  • I was looking for a quick, short, repeatable hash to use (non-secure). If you want the same, add `.toString(16)` to the result to convert it to hexadecimal and you will have a neat, small string you can reuse. – jsonUK Jun 13 '22 at 09:05
  • I'm using it for user agent hash and on Firefox 103.0.1 this strings gives a negative hash value: "'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:103.0) Gecko/20100101 Firefox/103.0'". – t.mikael.d Aug 19 '22 at 06:07
20

There are many realizations of hash functions written in JS. For example:

If you don't need security, you can also use base64 which is not hash-function, has not fixed output and could be simply decoded by user, but looks more lightweight and could be used for hide values: http://www.webtoolkit.info/javascript-base64.html

silex
  • 4,312
  • 4
  • 22
  • 27
  • 14
    base64 encoding of a string is more or less the same length as the original string; I'd like something that's shorter, like a hash. – mjs May 25 '11 at 10:27
  • 11
    base64 is even longer than the input, by the way to clarify that a bit more. – My1 Apr 11 '17 at 10:27
6

Simple object hasher:

(function () {
    Number.prototype.toHex = function () {
        var ret = ((this<0?0x8:0)+((this >> 28) & 0x7)).toString(16) + (this & 0xfffffff).toString(16);
        while (ret.length < 8) ret = '0'+ret;
        return ret;
    };
    Object.hashCode = function hashCode(o, l) {
        l = l || 2;
        var i, c, r = [];
        for (i=0; i<l; i++)
            r.push(i*268803292);
        function stringify(o) {
            var i,r;
            if (o === null) return 'n';
            if (o === true) return 't';
            if (o === false) return 'f';
            if (o instanceof Date) return 'd:'+(0+o);
            i=typeof o;
            if (i === 'string') return 's:'+o.replace(/([\\\\;])/g,'\\$1');
            if (i === 'number') return 'n:'+o;
            if (o instanceof Function) return 'm:'+o.toString().replace(/([\\\\;])/g,'\\$1');
            if (o instanceof Array) {
                r=[];
                for (i=0; i<o.length; i++) 
                    r.push(stringify(o[i]));
                return 'a:'+r.join(';');
            }
            r=[];
            for (i in o) {
                r.push(i+':'+stringify(o[i]))
            }
            return 'o:'+r.join(';');
        }
        o = stringify(o);
        for (i=0; i<o.length; i++) {
            for (c=0; c<r.length; c++) {
                r[c] = (r[c] << 13)-(r[c] >> 19);
                r[c] += o.charCodeAt(i) << (r[c] % 24);
                r[c] = r[c] & r[c];
            }
        }
        for (i=0; i<r.length; i++) {
            r[i] = r[i].toHex();
        }
        return r.join('');
    }
}());

The meat here is the stringifier, which simply converts any object into a unique string. hashCode then runs over the object, hashing together the characters of the stringified object.

For extra points, export the stringifier and create a parser.

Fordi
  • 2,798
  • 25
  • 20
  • any reason not to use JSON.stringify? – Jehan Aug 08 '14 at 23:31
  • 2
    March 2012. I couldn't, at the time, assume that JSON worked correctly in a certain browser. Also, JSON drops functions, so they wouldn't be hashable using JSON as your stringifier. – Fordi Aug 14 '14 at 20:09
2

Check out this MD5 implementation for JavaScript. Its BSD Licensed and really easy to use. Example:

md5 = hex_md5("message to digest")
jsalonen
  • 29,593
  • 15
  • 91
  • 109
  • I had found that, and it would work, but I was hoping for something smaller and simpler. Also, isn't the "message digest" the result of `hex_md5(message)`? – mjs May 25 '11 at 10:08
  • 1
    Yes digest is the result, the parameter is the message you want to digest - hence "message _to_ digest". – jsalonen May 25 '11 at 10:11
  • But anyway in which way you want the implementation to be simpler? That implementation is a simple JavaScript file with less then 400 lines. Do you just want a single function or what? – jsalonen May 25 '11 at 10:12
  • That makes more sense to me now; previously you had something like `hex_md5("message_digest") = "fb6cecc85a100197ae3ad68d1f9f2886"`, right? (Can't find the revision of your answer.) – mjs May 25 '11 at 10:31
  • Yes, I corrected that. But can you elaborate on the simplicity issue: in which way you want a simpler library? – jsalonen May 25 '11 at 10:32
2
// Simple but unreliable function to create string hash by Sergey.Shuchkin [t] gmail.com
// alert( strhash('http://www.w3schools.com/js/default.asp') ); // 6mn6tf7st333r2q4o134o58888888888
function strhash( str ) {
    if (str.length % 32 > 0) str += Array(33 - str.length % 32).join("z");
    var hash = '', bytes = [], i = 0, j = 0, k = 0, a = 0, dict = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','1','2','3','4','5','6','7','8','9'];
    for (i = 0; i < str.length; i++ ) {
        ch = str.charCodeAt(i);
        bytes[j++] = (ch < 127) ? ch & 0xFF : 127;
    }
    var chunk_len = Math.ceil(bytes.length / 32);   
    for (i=0; i<bytes.length; i++) {
        j += bytes[i];
        k++;
        if ((k == chunk_len) || (i == bytes.length-1)) {
            a = Math.floor( j / k );
            if (a < 32)
                hash += '0';
            else if (a > 126)
                hash += 'z';
            else
                hash += dict[  Math.floor( (a-32) / 2.76) ];
            j = k = 0;
        }
    }
    return hash;
}
Sergey Shuchkin
  • 2,037
  • 19
  • 9
  • 18
    This script will pollute the global scope with the following variables: `j`, `k`, `a`. The reason for this is because they are not a part of the `var` statement, merely a part of the expression that is evaluated to `var i`. Instead, use `var i, j, k, a; i = j = k = a = 0;`. – Niet the Dark Absol May 25 '12 at 08:05
  • 6
    Yes, the JS is poorly written, but it appears to directly address the OP's question and provides **example** code. Thank you! – mkoistinen Nov 30 '13 at 00:18