3

I have an array of objects in a JSON file. The objects don't have unique ids so I need to create either a unique id, or a unique string.

[
  {
    "name": "Jack Potts",
    "age": "56"
  }, {
    "name": "Rusty Carr",
    "age": "31"
  }
]

I know I can use MD5, passing in the object, but I'm going to use the string in a URL, so I'd prefer it to be shorter.

Rather than /people/3449c9e5e332f1dbb81505cd739fbf3f, I'd prefer something more like /people/1dbb81505.

It still needs to be a representation of the object because I'm going to lookup the person again from the URL.

Is there anything that produces a string shorter than the MD5 string..?

I'm going to guess that MD5 is my best/only option, but I thought I'd ask.

UPDATE

I maybe wasn't as clear as I could have been. I don't just need to generate a unique id. I won't be updating the JSON file with whatever I generate.

I need a way to take the object in question, create a URL for it, then when the URL is visited use the URL to get back to that object in the array.

As far as I know, if you pass in the same string to MD5 over and over, it will always return the same MD5 string because it's a representation. Don't people use this when storing passwords in a database for the same reason?

Maybe MD5 is fine, I just thought there might be something which produced a shorter string which is a representation of the data. That's my question.

UPDATE 2

The people in the array may change. People may be added and removed so using the array index won't work.

Stephen Last
  • 5,491
  • 9
  • 44
  • 85

6 Answers6

3

If you just want a shorter output that MD5 but are otherwise satisfied with the uniqueness just truncate to the length you need, each bit is as random as any other bit, that is any subset of the bits you choose are just as good as any other subset.

But realize that if two names are the same you will get the same hash.

As you must realize the shorter the hash the higher change of a collision, you are making a tradeoff of hash length vs uniqueness, that is not bad, just be sure you have enough uniqueness for your needs.

zaph
  • 111,848
  • 21
  • 189
  • 228
  • 1
    I like this answer... So I could use MD5 and just `str.substring(0, 10)` (for example). I can see now that my question wasn't worded very well, but this answer is what I needed. – Stephen Last Mar 01 '17 at 13:42
  • Yes on a string representation such as in the question. – zaph Mar 01 '17 at 14:52
0

Use the following function:

function generateUID() {
    var firstPart = (Math.random() * 46656) | 0;
    var secondPart = (Math.random() * 46656) | 0;
    firstPart = ("000" + firstPart.toString(36)).slice(-3);
    secondPart = ("000" + secondPart.toString(36)).slice(-3);
    return firstPart + secondPart;
}

A 6-character alphanumeric sequence is good enough to randomly index a 10k collection (366 = 2.2 billion and 363 = 46656).

Shakti Phartiyal
  • 6,156
  • 3
  • 25
  • 46
  • 1
    I've updated the question, I don't just need a unique id, it needs to be a **representation** of the object, like MD5 is. – Stephen Last Mar 01 '17 at 12:10
0

I suggest you use sha1, it proces a relatively short hash. Supposing your data set is relatively limited < 1000000000000...etc... items chances of collisions should be minimal.

https://github.com/emn178/js-sha1 is a nice library

edit modified this to make it shorter

It now does a substring, + a collision detection modification that should be dependable, as long as the order of the items doesn't change if they have the smae values. But then again, if they have the same values it shouldn't matter ;-)

/*
 * [js-sha1]{@link https://github.com/emn178/js-sha1}
 *
 * @version 0.4.1
 * @author Chen, Yi-Cyuan [emn178@gmail.com]
 * @copyright Chen, Yi-Cyuan 2014-2016
 * @license MIT
 */
/*jslint bitwise: true */
(function() {
  'use strict';

  var root = typeof window === 'object' ? window : {};
  var NODE_JS = !root.JS_SHA1_NO_NODE_JS && typeof process === 'object' && process.versions && process.versions.node;
  if (NODE_JS) {
    root = global;
  }
  var COMMON_JS = !root.JS_SHA1_NO_COMMON_JS && typeof module === 'object' && module.exports;
  var AMD = typeof define === 'function' && define.amd;
  var HEX_CHARS = '0123456789abcdef'.split('');
  var EXTRA = [-2147483648, 8388608, 32768, 128];
  var SHIFT = [24, 16, 8, 0];
  var OUTPUT_TYPES = ['hex', 'array', 'digest', 'arrayBuffer'];

  var blocks = [];

  var createOutputMethod = function (outputType) {
    return function (message) {
      return new Sha1(true).update(message)[outputType]();
    };
  };

  var createMethod = function () {
    var method = createOutputMethod('hex');
    if (NODE_JS) {
      method = nodeWrap(method);
    }
    method.create = function () {
      return new Sha1();
    };
    method.update = function (message) {
      return method.create().update(message);
    };
    for (var i = 0; i < OUTPUT_TYPES.length; ++i) {
      var type = OUTPUT_TYPES[i];
      method[type] = createOutputMethod(type);
    }
    return method;
  };

  var nodeWrap = function (method) {
    var crypto = require('crypto');
    var Buffer = require('buffer').Buffer;
    var nodeMethod = function (message) {
      if (typeof message === 'string') {
        return crypto.createHash('sha1').update(message, 'utf8').digest('hex');
      } else if (message.constructor === ArrayBuffer) {
        message = new Uint8Array(message);
      } else if (message.length === undefined) {
        return method(message);
      }
      return crypto.createHash('sha1').update(new Buffer(message)).digest('hex');
    };
    return nodeMethod;
  };

  function Sha1(sharedMemory) {
    if (sharedMemory) {
      blocks[0] = blocks[16] = blocks[1] = blocks[2] = blocks[3] =
      blocks[4] = blocks[5] = blocks[6] = blocks[7] =
      blocks[8] = blocks[9] = blocks[10] = blocks[11] =
      blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;
      this.blocks = blocks;
    } else {
      this.blocks = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
    }

    this.h0 = 0x67452301;
    this.h1 = 0xEFCDAB89;
    this.h2 = 0x98BADCFE;
    this.h3 = 0x10325476;
    this.h4 = 0xC3D2E1F0;

    this.block = this.start = this.bytes = 0;
    this.finalized = this.hashed = false;
    this.first = true;
  }

  Sha1.prototype.update = function (message) {
    if (this.finalized) {
      return;
    }
    var notString = typeof(message) !== 'string';
    if (notString && message.constructor === root.ArrayBuffer) {
      message = new Uint8Array(message);
    }
    var code, index = 0, i, length = message.length || 0, blocks = this.blocks;

    while (index < length) {
      if (this.hashed) {
        this.hashed = false;
        blocks[0] = this.block;
        blocks[16] = blocks[1] = blocks[2] = blocks[3] =
        blocks[4] = blocks[5] = blocks[6] = blocks[7] =
        blocks[8] = blocks[9] = blocks[10] = blocks[11] =
        blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;
      }

      if(notString) {
        for (i = this.start; index < length && i < 64; ++index) {
          blocks[i >> 2] |= message[index] << SHIFT[i++ & 3];
        }
      } else {
        for (i = this.start; index < length && i < 64; ++index) {
          code = message.charCodeAt(index);
          if (code < 0x80) {
            blocks[i >> 2] |= code << SHIFT[i++ & 3];
          } else if (code < 0x800) {
            blocks[i >> 2] |= (0xc0 | (code >> 6)) << SHIFT[i++ & 3];
            blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];
          } else if (code < 0xd800 || code >= 0xe000) {
            blocks[i >> 2] |= (0xe0 | (code >> 12)) << SHIFT[i++ & 3];
            blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3];
            blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];
          } else {
            code = 0x10000 + (((code & 0x3ff) << 10) | (message.charCodeAt(++index) & 0x3ff));
            blocks[i >> 2] |= (0xf0 | (code >> 18)) << SHIFT[i++ & 3];
            blocks[i >> 2] |= (0x80 | ((code >> 12) & 0x3f)) << SHIFT[i++ & 3];
            blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3];
            blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];
          }
        }
      }

      this.lastByteIndex = i;
      this.bytes += i - this.start;
      if (i >= 64) {
        this.block = blocks[16];
        this.start = i - 64;
        this.hash();
        this.hashed = true;
      } else {
        this.start = i;
      }
    }
    return this;
  };

  Sha1.prototype.finalize = function () {
    if (this.finalized) {
      return;
    }
    this.finalized = true;
    var blocks = this.blocks, i = this.lastByteIndex;
    blocks[16] = this.block;
    blocks[i >> 2] |= EXTRA[i & 3];
    this.block = blocks[16];
    if (i >= 56) {
      if (!this.hashed) {
        this.hash();
      }
      blocks[0] = this.block;
      blocks[16] = blocks[1] = blocks[2] = blocks[3] =
      blocks[4] = blocks[5] = blocks[6] = blocks[7] =
      blocks[8] = blocks[9] = blocks[10] = blocks[11] =
      blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;
    }
    blocks[15] = this.bytes << 3;
    this.hash();
  };

  Sha1.prototype.hash = function () {
    var a = this.h0, b = this.h1, c = this.h2, d = this.h3, e = this.h4;
    var f, j, t, blocks = this.blocks;

    for(j = 16; j < 80; ++j) {
      t = blocks[j - 3] ^ blocks[j - 8] ^ blocks[j - 14] ^ blocks[j - 16];
      blocks[j] =  (t << 1) | (t >>> 31);
    }

    for(j = 0; j < 20; j += 5) {
      f = (b & c) | ((~b) & d);
      t = (a << 5) | (a >>> 27);
      e = t + f + e + 1518500249 + blocks[j] << 0;
      b = (b << 30) | (b >>> 2);

      f = (a & b) | ((~a) & c);
      t = (e << 5) | (e >>> 27);
      d = t + f + d + 1518500249 + blocks[j + 1] << 0;
      a = (a << 30) | (a >>> 2);

      f = (e & a) | ((~e) & b);
      t = (d << 5) | (d >>> 27);
      c = t + f + c + 1518500249 + blocks[j + 2] << 0;
      e = (e << 30) | (e >>> 2);

      f = (d & e) | ((~d) & a);
      t = (c << 5) | (c >>> 27);
      b = t + f + b + 1518500249 + blocks[j + 3] << 0;
      d = (d << 30) | (d >>> 2);

      f = (c & d) | ((~c) & e);
      t = (b << 5) | (b >>> 27);
      a = t + f + a + 1518500249 + blocks[j + 4] << 0;
      c = (c << 30) | (c >>> 2);
    }

    for(; j < 40; j += 5) {
      f = b ^ c ^ d;
      t = (a << 5) | (a >>> 27);
      e = t + f + e + 1859775393 + blocks[j] << 0;
      b = (b << 30) | (b >>> 2);

      f = a ^ b ^ c;
      t = (e << 5) | (e >>> 27);
      d = t + f + d + 1859775393 + blocks[j + 1] << 0;
      a = (a << 30) | (a >>> 2);

      f = e ^ a ^ b;
      t = (d << 5) | (d >>> 27);
      c = t + f + c + 1859775393 + blocks[j + 2] << 0;
      e = (e << 30) | (e >>> 2);

      f = d ^ e ^ a;
      t = (c << 5) | (c >>> 27);
      b = t + f + b + 1859775393 + blocks[j + 3] << 0;
      d = (d << 30) | (d >>> 2);

      f = c ^ d ^ e;
      t = (b << 5) | (b >>> 27);
      a = t + f + a + 1859775393 + blocks[j + 4] << 0;
      c = (c << 30) | (c >>> 2);
    }

    for(; j < 60; j += 5) {
      f = (b & c) | (b & d) | (c & d);
      t = (a << 5) | (a >>> 27);
      e = t + f + e - 1894007588 + blocks[j] << 0;
      b = (b << 30) | (b >>> 2);

      f = (a & b) | (a & c) | (b & c);
      t = (e << 5) | (e >>> 27);
      d = t + f + d - 1894007588 + blocks[j + 1] << 0;
      a = (a << 30) | (a >>> 2);

      f = (e & a) | (e & b) | (a & b);
      t = (d << 5) | (d >>> 27);
      c = t + f + c - 1894007588 + blocks[j + 2] << 0;
      e = (e << 30) | (e >>> 2);

      f = (d & e) | (d & a) | (e & a);
      t = (c << 5) | (c >>> 27);
      b = t + f + b - 1894007588 + blocks[j + 3] << 0;
      d = (d << 30) | (d >>> 2);

      f = (c & d) | (c & e) | (d & e);
      t = (b << 5) | (b >>> 27);
      a = t + f + a - 1894007588 + blocks[j + 4] << 0;
      c = (c << 30) | (c >>> 2);
    }

    for(; j < 80; j += 5) {
      f = b ^ c ^ d;
      t = (a << 5) | (a >>> 27);
      e = t + f + e - 899497514 + blocks[j] << 0;
      b = (b << 30) | (b >>> 2);

      f = a ^ b ^ c;
      t = (e << 5) | (e >>> 27);
      d = t + f + d - 899497514 + blocks[j + 1] << 0;
      a = (a << 30) | (a >>> 2);

      f = e ^ a ^ b;
      t = (d << 5) | (d >>> 27);
      c = t + f + c - 899497514 + blocks[j + 2] << 0;
      e = (e << 30) | (e >>> 2);

      f = d ^ e ^ a;
      t = (c << 5) | (c >>> 27);
      b = t + f + b - 899497514 + blocks[j + 3] << 0;
      d = (d << 30) | (d >>> 2);

      f = c ^ d ^ e;
      t = (b << 5) | (b >>> 27);
      a = t + f + a - 899497514 + blocks[j + 4] << 0;
      c = (c << 30) | (c >>> 2);
    }

    this.h0 = this.h0 + a << 0;
    this.h1 = this.h1 + b << 0;
    this.h2 = this.h2 + c << 0;
    this.h3 = this.h3 + d << 0;
    this.h4 = this.h4 + e << 0;
  };

  Sha1.prototype.hex = function () {
    this.finalize();

    var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3, h4 = this.h4;

    return HEX_CHARS[(h0 >> 28) & 0x0F] + HEX_CHARS[(h0 >> 24) & 0x0F] +
           HEX_CHARS[(h0 >> 20) & 0x0F] + HEX_CHARS[(h0 >> 16) & 0x0F] +
           HEX_CHARS[(h0 >> 12) & 0x0F] + HEX_CHARS[(h0 >> 8) & 0x0F] +
           HEX_CHARS[(h0 >> 4) & 0x0F] + HEX_CHARS[h0 & 0x0F] +
           HEX_CHARS[(h1 >> 28) & 0x0F] + HEX_CHARS[(h1 >> 24) & 0x0F] +
           HEX_CHARS[(h1 >> 20) & 0x0F] + HEX_CHARS[(h1 >> 16) & 0x0F] +
           HEX_CHARS[(h1 >> 12) & 0x0F] + HEX_CHARS[(h1 >> 8) & 0x0F] +
           HEX_CHARS[(h1 >> 4) & 0x0F] + HEX_CHARS[h1 & 0x0F] +
           HEX_CHARS[(h2 >> 28) & 0x0F] + HEX_CHARS[(h2 >> 24) & 0x0F] +
           HEX_CHARS[(h2 >> 20) & 0x0F] + HEX_CHARS[(h2 >> 16) & 0x0F] +
           HEX_CHARS[(h2 >> 12) & 0x0F] + HEX_CHARS[(h2 >> 8) & 0x0F] +
           HEX_CHARS[(h2 >> 4) & 0x0F] + HEX_CHARS[h2 & 0x0F] +
           HEX_CHARS[(h3 >> 28) & 0x0F] + HEX_CHARS[(h3 >> 24) & 0x0F] +
           HEX_CHARS[(h3 >> 20) & 0x0F] + HEX_CHARS[(h3 >> 16) & 0x0F] +
           HEX_CHARS[(h3 >> 12) & 0x0F] + HEX_CHARS[(h3 >> 8) & 0x0F] +
           HEX_CHARS[(h3 >> 4) & 0x0F] + HEX_CHARS[h3 & 0x0F] +
           HEX_CHARS[(h4 >> 28) & 0x0F] + HEX_CHARS[(h4 >> 24) & 0x0F] +
           HEX_CHARS[(h4 >> 20) & 0x0F] + HEX_CHARS[(h4 >> 16) & 0x0F] +
           HEX_CHARS[(h4 >> 12) & 0x0F] + HEX_CHARS[(h4 >> 8) & 0x0F] +
           HEX_CHARS[(h4 >> 4) & 0x0F] + HEX_CHARS[h4 & 0x0F];
  };

  Sha1.prototype.toString = Sha1.prototype.hex;

  Sha1.prototype.digest = function () {
    this.finalize();

    var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3, h4 = this.h4;

    return [
      (h0 >> 24) & 0xFF, (h0 >> 16) & 0xFF, (h0 >> 8) & 0xFF, h0 & 0xFF,
      (h1 >> 24) & 0xFF, (h1 >> 16) & 0xFF, (h1 >> 8) & 0xFF, h1 & 0xFF,
      (h2 >> 24) & 0xFF, (h2 >> 16) & 0xFF, (h2 >> 8) & 0xFF, h2 & 0xFF,
      (h3 >> 24) & 0xFF, (h3 >> 16) & 0xFF, (h3 >> 8) & 0xFF, h3 & 0xFF,
      (h4 >> 24) & 0xFF, (h4 >> 16) & 0xFF, (h4 >> 8) & 0xFF, h4 & 0xFF
    ];
  };

  Sha1.prototype.array = Sha1.prototype.digest;

  Sha1.prototype.arrayBuffer = function () {
    this.finalize();

    var buffer = new ArrayBuffer(20);
    var dataView = new DataView(buffer);
    dataView.setUint32(0, this.h0);
    dataView.setUint32(4, this.h1);
    dataView.setUint32(8, this.h2);
    dataView.setUint32(12, this.h3);
    dataView.setUint32(16, this.h4);
    return buffer;
  };

  var exports = createMethod();

  if (COMMON_JS) {
    module.exports = exports;
  } else {
    root.sha1 = exports;
    if (AMD) {
      define(function () {
        return exports;
      });
    }
  }
})();
+function() {
   var HASHLENGTH = 5;
   document.getElementById('clickme').onclick = function() {
     // get all the values as objects
     var values = JSON.parse(document.getElementById('sample').value);

     for (var c = 0; c < values.length; c++) {
         // Hash it and substring it given the hashlength
         values[c].hash = sha1(JSON.stringify(values[c])).substring(0,HASHLENGTH);
         // If you don't need the collision detection, you can just remove these loops.
         // check for collisions
         for(var i = 0;i < c; i++) {
             // collision detected. add a dependable value to get a new hash.
             if(values[i].hash == values[c].hash) {
                if(values[c].hasOwnProperty('_change')) {
                    values[c]._change = sha1(values[c]._change);
                }
                else {
                    values[c]._change = sha1(values[c].hash);
                }
                c--;break; // return to same thing for a rehash
             }
         }
     }
     console.log(JSON.stringify(values,null,4));
  }
}();
textarea { width:100%;height:200px;}
<button id="clickme"> Parse </button>
<textarea id="sample">
[
  {
    "name": "Jack Potts",
    "age": "56"
  }, {
    "name": "Rusty Carr",
    "age": "31"
  },
  {
    "name": "Rusty Carr",
    "age": "31"
  },
  {
    "name": "Rusty Carr",
    "age": "31"
  },
  {
    "name": "Rusty Carr",
    "age": "31"
  },
  {
    "name": "Rusty Carr",
    "age": "31"
  },
  {
    "name": "Rusty Carr",
    "age": "31"
  }
]
</textarea>
Tschallacka
  • 27,901
  • 14
  • 88
  • 133
  • That seems to produce a hash just as long, if not longer than MD5. My question is specifically about a shorter version of MD5. – Stephen Last Mar 01 '17 at 12:25
  • usually what's done is a substring of the hash really. so if you do a 5 letter substring you have 16x16x16x16x16 (1048576) possiblities of combinations of characters. With a javascript dataset that gives enough flexiblity. And if there is a collsion you can easely check and modify the object by adding a value to make it non collidable. I'll modify my example to show that. – Tschallacka Mar 01 '17 at 12:28
  • @StephenLast I modified my example with a substring + double collision detection. that should be robust enough for real world implementations. – Tschallacka Mar 01 '17 at 12:46
  • 1
    1. Always use a method from a well vetted library, not code. 2. What is * double collision detection*, please explain – zaph Mar 01 '17 at 13:19
  • I used the sha1 code from a well vetted library as you can easily see, even provided the link to it. Also, the "code" is a simple substring. The double collsion detection makes it so that each item gets a second calculated unique hash depending on the occurence point. first time based on the calculated hash, second time a double is found based on the existing hash in the object, but if you read the code, you saw he could remove it since op stated that duplicate items are allowed to have the same hash. I just added it as a feature. – Tschallacka Mar 01 '17 at 13:36
  • @Tschallacka Thanks. It's interesting to look at your code. Really though, the simple answer is to just use `str.substring()` and understand the trade off you have to accept, which was put really well by @zaph. – Stephen Last Mar 01 '17 at 13:48
0

I won't be updating the JSON file with whatever I generate.

I need a way to take the object in question, create a URL for it, then when the URL is visited use the URL to get back to that object in the array.

Then use the index of the object in the array: that way people/0 will return {"name": "Jack Potts", "age": "56"}, people/1 will return {"name": "Rusty Carr", "age": "31"}, and so on...

Community
  • 1
  • 1
  • That would work so long as the people in the JSON array don't change, which in my case, they might. People may be added and removed and the URL needs to point to correct person. I'll update my question with that - sorry! – Stephen Last Mar 01 '17 at 12:19
0

Here is native JavaScript code to get an MD5 hash, shortened to a desired length. Mind you, the shorter the hash, the more likely you get collisions.

var md5 = function(d){var r = M(V(Y(X(d),8*d.length)));return r.toLowerCase()};function M(d){for(var _,m="0123456789ABCDEF",f="",r=0;r<d.length;r++)_=d.charCodeAt(r),f+=m.charAt(_>>>4&15)+m.charAt(15&_);return f}function X(d){for(var _=Array(d.length>>2),m=0;m<_.length;m++)_[m]=0;for(m=0;m<8*d.length;m+=8)_[m>>5]|=(255&d.charCodeAt(m/8))<<m%32;return _}function V(d){for(var _="",m=0;m<32*d.length;m+=8)_+=String.fromCharCode(d[m>>5]>>>m%32&255);return _}function Y(d,_){d[_>>5]|=128<<_%32,d[14+(_+64>>>9<<4)]=_;for(var m=1732584193,f=-271733879,r=-1732584194,i=271733878,n=0;n<d.length;n+=16){var h=m,t=f,g=r,e=i;f=md5_ii(f=md5_ii(f=md5_ii(f=md5_ii(f=md5_hh(f=md5_hh(f=md5_hh(f=md5_hh(f=md5_gg(f=md5_gg(f=md5_gg(f=md5_gg(f=md5_ff(f=md5_ff(f=md5_ff(f=md5_ff(f,r=md5_ff(r,i=md5_ff(i,m=md5_ff(m,f,r,i,d[n+0],7,-680876936),f,r,d[n+1],12,-389564586),m,f,d[n+2],17,606105819),i,m,d[n+3],22,-1044525330),r=md5_ff(r,i=md5_ff(i,m=md5_ff(m,f,r,i,d[n+4],7,-176418897),f,r,d[n+5],12,1200080426),m,f,d[n+6],17,-1473231341),i,m,d[n+7],22,-45705983),r=md5_ff(r,i=md5_ff(i,m=md5_ff(m,f,r,i,d[n+8],7,1770035416),f,r,d[n+9],12,-1958414417),m,f,d[n+10],17,-42063),i,m,d[n+11],22,-1990404162),r=md5_ff(r,i=md5_ff(i,m=md5_ff(m,f,r,i,d[n+12],7,1804603682),f,r,d[n+13],12,-40341101),m,f,d[n+14],17,-1502002290),i,m,d[n+15],22,1236535329),r=md5_gg(r,i=md5_gg(i,m=md5_gg(m,f,r,i,d[n+1],5,-165796510),f,r,d[n+6],9,-1069501632),m,f,d[n+11],14,643717713),i,m,d[n+0],20,-373897302),r=md5_gg(r,i=md5_gg(i,m=md5_gg(m,f,r,i,d[n+5],5,-701558691),f,r,d[n+10],9,38016083),m,f,d[n+15],14,-660478335),i,m,d[n+4],20,-405537848),r=md5_gg(r,i=md5_gg(i,m=md5_gg(m,f,r,i,d[n+9],5,568446438),f,r,d[n+14],9,-1019803690),m,f,d[n+3],14,-187363961),i,m,d[n+8],20,1163531501),r=md5_gg(r,i=md5_gg(i,m=md5_gg(m,f,r,i,d[n+13],5,-1444681467),f,r,d[n+2],9,-51403784),m,f,d[n+7],14,1735328473),i,m,d[n+12],20,-1926607734),r=md5_hh(r,i=md5_hh(i,m=md5_hh(m,f,r,i,d[n+5],4,-378558),f,r,d[n+8],11,-2022574463),m,f,d[n+11],16,1839030562),i,m,d[n+14],23,-35309556),r=md5_hh(r,i=md5_hh(i,m=md5_hh(m,f,r,i,d[n+1],4,-1530992060),f,r,d[n+4],11,1272893353),m,f,d[n+7],16,-155497632),i,m,d[n+10],23,-1094730640),r=md5_hh(r,i=md5_hh(i,m=md5_hh(m,f,r,i,d[n+13],4,681279174),f,r,d[n+0],11,-358537222),m,f,d[n+3],16,-722521979),i,m,d[n+6],23,76029189),r=md5_hh(r,i=md5_hh(i,m=md5_hh(m,f,r,i,d[n+9],4,-640364487),f,r,d[n+12],11,-421815835),m,f,d[n+15],16,530742520),i,m,d[n+2],23,-995338651),r=md5_ii(r,i=md5_ii(i,m=md5_ii(m,f,r,i,d[n+0],6,-198630844),f,r,d[n+7],10,1126891415),m,f,d[n+14],15,-1416354905),i,m,d[n+5],21,-57434055),r=md5_ii(r,i=md5_ii(i,m=md5_ii(m,f,r,i,d[n+12],6,1700485571),f,r,d[n+3],10,-1894986606),m,f,d[n+10],15,-1051523),i,m,d[n+1],21,-2054922799),r=md5_ii(r,i=md5_ii(i,m=md5_ii(m,f,r,i,d[n+8],6,1873313359),f,r,d[n+15],10,-30611744),m,f,d[n+6],15,-1560198380),i,m,d[n+13],21,1309151649),r=md5_ii(r,i=md5_ii(i,m=md5_ii(m,f,r,i,d[n+4],6,-145523070),f,r,d[n+11],10,-1120210379),m,f,d[n+2],15,718787259),i,m,d[n+9],21,-343485551),m=safe_add(m,h),f=safe_add(f,t),r=safe_add(r,g),i=safe_add(i,e)}return Array(m,f,r,i)}function md5_cmn(d,_,m,f,r,i){return safe_add(bit_rol(safe_add(safe_add(_,d),safe_add(f,i)),r),m)}function md5_ff(d,_,m,f,r,i,n){return md5_cmn(_&m|~_&f,d,_,r,i,n)}function md5_gg(d,_,m,f,r,i,n){return md5_cmn(_&f|m&~f,d,_,r,i,n)}function md5_hh(d,_,m,f,r,i,n){return md5_cmn(_^m^f,d,_,r,i,n)}function md5_ii(d,_,m,f,r,i,n){return md5_cmn(m^(_|~f),d,_,r,i,n)}function safe_add(d,_){var m=(65535&d)+(65535&_);return(d>>16)+(_>>16)+(m>>16)<<16|65535&m}function bit_rol(d,_){return d<<_|d>>>32-_}

function tinymd5(str, length) {
    length = length || 16;
    str = window.btoa(md5(str)).replace(/[aiueoAIUEO\+\/]/g, '').substring(0, length);
    if(str.length < length) {
        str += Array(length - str.length).join('=');
    }
    return str;
}

// example usage:
var shortHash = tinymd5(JSON.stringify(someObj), 16);

The md5 function is from https://stackoverflow.com/a/33486055/7475450

The tinymd5 function is code converted to JavaScript based on https://rolandeckert.com/notes/md5

Peter Thoeny
  • 7,379
  • 1
  • 10
  • 20
0

Maybe it works using 3125 chars :

const md5=str=>{var a=(r,t)=>r+t&0xffffffff,l=(r,t)=>{var e=r[0],n=r[1],o=r[2],l=r[3],e=h(e,n,o,l,t[0],7,-0x28955b88),l=h(l,e,n,o,t[1],12,-0x173848aa),o=h(o,l,e,n,t[2],17,0x242070db),n=h(n,o,l,e,t[3],22,-0x3e423112);e=h(e,n,o,l,t[4],7,-0xa83f051),l=h(l,e,n,o,t[5],12,0x4787c62a),o=h(o,l,e,n,t[6],17,-0x57cfb9ed),n=h(n,o,l,e,t[7],22,-0x2b96aff),e=h(e,n,o,l,t[8],7,0x698098d8),l=h(l,e,n,o,t[9],12,-0x74bb0851),o=h(o,l,e,n,t[10],17,-42063),n=h(n,o,l,e,t[11],22,-0x76a32842),e=h(e,n,o,l,t[12],7,0x6b901122),l=h(l,e,n,o,t[13],12,-0x2678e6d),o=h(o,l,e,n,t[14],17,-0x5986bc72),n=h(n,o,l,e,t[15],22,0x49b40821),e=c(e,n,o,l,t[1],5,-0x9e1da9e),l=c(l,e,n,o,t[6],9,-0x3fbf4cc0),o=c(o,l,e,n,t[11],14,0x265e5a51),n=c(n,o,l,e,t[0],20,-0x16493856),e=c(e,n,o,l,t[5],5,-0x29d0efa3),l=c(l,e,n,o,t[10],9,0x2441453),o=c(o,l,e,n,t[15],14,-0x275e197f),n=c(n,o,l,e,t[4],20,-0x182c0438),e=c(e,n,o,l,t[9],5,0x21e1cde6),l=c(l,e,n,o,t[14],9,-0x3cc8f82a),o=c(o,l,e,n,t[3],14,-0xb2af279),n=c(n,o,l,e,t[8],20,0x455a14ed),e=c(e,n,o,l,t[13],5,-0x561c16fb),l=c(l,e,n,o,t[2],9,-0x3105c08),o=c(o,l,e,n,t[7],14,0x676f02d9),n=c(n,o,l,e,t[12],20,-0x72d5b376),e=d(e,n,o,l,t[5],4,-378558),l=d(l,e,n,o,t[8],11,-0x788e097f),o=d(o,l,e,n,t[11],16,0x6d9d6122),n=d(n,o,l,e,t[14],23,-0x21ac7f4),e=d(e,n,o,l,t[1],4,-0x5b4115bc),l=d(l,e,n,o,t[4],11,0x4bdecfa9),o=d(o,l,e,n,t[7],16,-0x944b4a0),n=d(n,o,l,e,t[10],23,-0x41404390),e=d(e,n,o,l,t[13],4,0x289b7ec6),l=d(l,e,n,o,t[0],11,-0x155ed806),o=d(o,l,e,n,t[3],16,-0x2b10cf7b),n=d(n,o,l,e,t[6],23,0x4881d05),e=d(e,n,o,l,t[9],4,-0x262b2fc7),l=d(l,e,n,o,t[12],11,-0x1924661b),o=d(o,l,e,n,t[15],16,0x1fa27cf8),n=d(n,o,l,e,t[2],23,-0x3b53a99b),e=g(e,n,o,l,t[0],6,-0xbd6ddbc),l=g(l,e,n,o,t[7],10,0x432aff97),o=g(o,l,e,n,t[14],15,-0x546bdc59),n=g(n,o,l,e,t[5],21,-0x36c5fc7),e=g(e,n,o,l,t[12],6,0x655b59c3),l=g(l,e,n,o,t[3],10,-0x70f3336e),o=g(o,l,e,n,t[10],15,-0x100b83),n=g(n,o,l,e,t[1],21,-0x7a7ba22f),e=g(e,n,o,l,t[8],6,0x6fa87e4f),l=g(l,e,n,o,t[15],10,-0x1d31920),o=g(o,l,e,n,t[6],15,-0x5cfebcec),n=g(n,o,l,e,t[13],21,0x4e0811a1),e=g(e,n,o,l,t[4],6,-0x8ac817e),l=g(l,e,n,o,t[11],10,-0x42c50dcb),o=g(o,l,e,n,t[2],15,0x2ad7d2bb),n=g(n,o,l,e,t[9],21,-0x14792c6f),r[0]=a(e,r[0]),r[1]=a(n,r[1]),r[2]=a(o,r[2]),r[3]=a(l,r[3])},f=(r,t,e,n,o,l)=>(t=a(a(t,r),a(n,l)),a(t<<o|t>>>32-o,e));let h=(r,t,e,n,o,l,a)=>f(t&e|~t&n,r,t,o,l,a),c=(r,t,e,n,o,l,a)=>f(t&n|e&~n,r,t,o,l,a),d=(r,t,e,n,o,l,a)=>f(t^e^n,r,t,o,l,a),g=(r,t,e,n,o,l,a)=>f(e^(t|~n),r,t,o,l,a);var n="0123456789abcdef".split("");return(t=>{for(let r=0;r<t.length;r++)t[r]=(r=>{let t="",e=0;for(;e<4;e++)t+=n[r>>8*e+4&15]+n[r>>8*e&15];return t})(t[r]);return t.join("")})((r=>{let t=r.length,e=[0x67452301,-0x10325477,-0x67452302,0x10325476],n;for(n=64;n<=r.length;n+=64)l(e,(r=>{let t=[],e;for(e=0;e<64;e+=4)t[e>>2]=r.charCodeAt(e)+(r.charCodeAt(e+1)<<8)+(r.charCodeAt(e+2)<<16)+(r.charCodeAt(e+3)<<24);return t})(r.substring(n-64,n)));r=r.substring(n-64);let o=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];for(n=0;n<r.length;n++)o[n>>2]|=r.charCodeAt(n)<<(n%4<<3);if(o[n>>2]|=128<<(n%4<<3),55<n)for(l(e,o),n=0;n<16;n++)o[n]=0;return o[14]=8*t,l(e,o),e})("string"==typeof str?str:""+str))};
mike
  • 1
  • 1