UUID generator genius



  • anonymized.uuid = function() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
    var r = Math.random() * 16 | 0,
    v = c == 'x' ? r : (r & 0x3 | 0x8);
    return v.toString(16);
    });
    };

    Found this unique method for generating UUID's in another vendor's Javascript codebase. For comparison, my company uses this. I'm no mathematician but I'm fairly sure this isn't the recommended way for creating one of those.


  • FoxDev

    hmm.... that code looks familliar....

    https://github.com/SockDrawer/SockBot/blob/master/discourse.js#L17-L35

    it generates valid type 4 UUIDs



  • If we assume for the moment that Math.random() is a cryptographic-quality RNG, then that absolutely is the recommended and correct way to create one of those. Unfortunately, that assumption is not valid.

    SockBot should be using the builtin Node.js crypto module, and intranet apps that only need to support Firefox and Chrome should be using window.crypto.getRandomValues(), but those RNGs aren't always available, in which case uuid.js falls right back to using Math.random() and does literally this, but written funnier.


  • I survived the hour long Uno hand

    @aapis said:

    my company uses this

    On an unrelated note, those are really nice docs, and I've seen that style in a number of places. I would assume those are generated somehow -- anyone know how?



  • My preferred method:

    /**
     * Fast UUID generator, RFC4122 version 4 compliant.
     * @author Jeff Ward (jcward.com).
     * @license MIT license
     * @link http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/21963136#21963136
     **/
    utils.UUID = (function () {
        var self = {};
        var lut = []; for (var i = 0; i < 256; i++) { lut[i] = (i < 16 ? '0' : '') + (i).toString(16); }
        self.generate = function () {
            if ((typeof (window.crypto) != 'undefined' && typeof (window.crypto.getRandomValues) != 'undefined')) {
                return self.crypto_();
            }
            return self.math_();
        };
        self.crypto_ = function () {
            var buf = new Uint16Array(8);
            window.crypto.getRandomValues(buf);
            var S4 = function (num) {
                var ret = num.toString(16);
                while (ret.length < 4) {
                    ret = "0" + ret;
                }
                return ret;
            };
            return (S4(buf[0]) + S4(buf[1]) + "-" + S4(buf[2]) + "-4" + S4(buf[3]).substr(0, 3) + "-" + S4(buf[4]) + "-" + S4(buf[5]) + S4(buf[6]) + S4(buf[7]));
        };
        self.math_ = function () {
            var d0 = Math.random() * 0xffffffff | 0;
            var d1 = Math.random() * 0xffffffff | 0;
            var d2 = Math.random() * 0xffffffff | 0;
            var d3 = Math.random() * 0xffffffff | 0;
            return lut[d0 & 0xff] + lut[d0 >> 8 & 0xff] + lut[d0 >> 16 & 0xff] + lut[d0 >> 24 & 0xff] + '-' +
              lut[d1 & 0xff] + lut[d1 >> 8 & 0xff] + '-' + lut[d1 >> 16 & 0x0f | 0x40] + lut[d1 >> 24 & 0xff] + '-' +
              lut[d2 & 0x3f | 0x80] + lut[d2 >> 8 & 0xff] + '-' + lut[d2 >> 16 & 0xff] + lut[d2 >> 24 & 0xff] +
              lut[d3 & 0xff] + lut[d3 >> 8 & 0xff] + lut[d3 >> 16 & 0xff] + lut[d3 >> 24 & 0xff];
        }
        return self;
    })();
    

    This does basically the same thing as what @TwelveBaud said


  • FoxDev

    If all you need is an RNG, why have the overhead of a CRNG?



  • @Yamikuronue said:

    On an unrelated note, those are really nice docs, and I've seen that style in a number of places. I would assume those are generated somehow -- anyone know how?


  • I survived the hour long Uno hand

    Nice, thanks!



  • Because a CRNG takes steps to ensure that it's uniquely seeded, that it doesn't run out of entropy, and other such properties. On most computers, the basic RNG gets its seed solely from the current time, so if two computers had accurate, synchronized clocks they'd generate the same random numbers. A CRNG would instead wait until it had acquired more "noise" (thermal fluctuations in the CPU, microseconds between electrical pulses on the Ethernet, stuff fed in from a uniquely-keyed TPM) thus ensuring the numbers would almost certainly be different.

    You could alternatively generate Type 1 UUIDs, combining aspects of space (network card MAC address) and time (current time in milliseconds) directly, which would always be unique, but this has privacy implications and doesn't work too well on systems without a hardware network card.


  • Discourse touched me in a no-no place

    @TwelveBaud said:

    If we assume for the moment that Math.random() is a cryptographic-quality RNG, then that absolutely is the recommended and correct way to create one of those. Unfortunately, that assumption is not valid.

    Why not just use this? (or similar)


  • FoxDev

    @TwelveBaud said:

    Unfortunately, that assumption is not valid.

    it's not an assumption i made actually.

    all SockBot cares about it that it has a valid type4 UUID that discourse accepts.

    of course if you want to issue PR adding node-uuid as a dependency then... well more power to you! i'll happily accept that!

    in the mean time this works and is not being used for purposes that need the uniqueness of a better generated UUID ;-)


  • FoxDev

    All true, but only an issue if you're concerned about security; I'm not convinced that's necessary for SockBot.

    Edit: :hanzo: d by my queen...



  • Mersenne Twister is cool if you want predictable random numbers, and I and several companies have used it for license keys or keeping games in sync, but does not include any sort of entropy pool. Two machines with synchronized clocks will get the same seed value and always produce the same numbers forever thereafter.



  • @accalia said:

    all SockBot cares about it that it has a valid type4 UUID that discourse accepts.
    @RaceProUK said:
    I'm not convinced that's necessary for SockBot.
    I don't think Discourse uses it as a primary key anywhere (@riking?), so SockBot should be absolutely fine without it.



  • I still haven't seen any evidence that the probability of a "bad" RNG generating the same 31 numbers twice is anything but negligible.



  • UUIDs get used for lots of things, and some of those things become insecure if your UUID generator produces in-principle predictable sequences. For example:

    Using the bottom four bits of a bunch of successive PRNs instead of the numbers in their entirety looks like the kind of thing that ought to make the sequence less predictable, but it isn't.



  • Back in college I wrote a particle simulation in C/Win32/DirectX just for fun, mostly to play with the gravity equations I learned in Classical Physics. I used a PRNG to randomize the vector of new particles at application startup, and I found that the stock C runtime PRNG was horrible. New particles tended to form discrete streams as the same random vectors got selected over and over again, and it looked horrible.

    I swapped out the PRNG for the Mersenne Twister and after that it actually looked random. No more particle streams.

    Moral of the story: pick the right PRNG for your particular task.


  • kills Dumbledore

    @accalia said:

    all SockBot cares about it that it has a valid type4 UUID that discourse accepts.

    Why not generate one from www.wasteaguid.info and hard code it then?


  • FoxDev

    because it needs to be different for each bot instance.


  • FoxDev

    It's used to initiate the session, is it not?



  • @mott555 said:

    Back in college I wrote a particle simulation in C/Win32/DirectX just for fun, mostly to play with the gravity equations I learned in Classical Physics. I used a PRNG to randomize the vector of new particles at application startup, and I found that the stock C runtime PRNG was horrible. New particles tended to form discrete streams as the same random vectors got selected over and over again, and it looked horrible

    A great visualizer for looking at complex data!



  • @TwelveBaud said:

    I don't think Discourse uses it as a primary key anywhere (@riking?), so SockBot should be absolutely fine without it.

    Unless somewhere in the universe someone gathers data from billions of sources each with billions of entries and counts on the "global"/"universal" uniqueness.....



  • I recognize that code. I'm using it in my node project.

    Lately npm started warning me that this lib is crap and I should switch to node's native uuid generator. One of these days I might do that.


  • FoxDev

    message-buss needs it


  • Discourse touched me in a no-no place

    @TwelveBaud said:

    Mersenne Twister is cool if you want predictable random numbers

    It's more commonly used with a CRNG (or the system entropy pool) seeding it, so that there's a reasonably strong normal PRNG that's still unpredictable. The effective cycle time of the MT algorithm is then long enough that waiting for a predictable subsequence isn't worthwhile.



  • @TwelveBaud said:

    If we assume for the moment that Math.random() is a cryptographic-quality RNG, then that absolutely is the recommended and correct way to create one of those. Unfortunately, that assumption is not valid.

    Exactly true.

    From here, for Javascript:

    Note: Math.random() does not provide cryptographically secure random numbers. Do not use them for anything related to security. Use the Web Crypto API instead, and more precisely the window.crypto.getRandomValues() method.

    From here, for Java SE 8:

    Instances of java.util.Random are not cryptographically secure. Consider instead using SecureRandom to get a cryptographically secure pseudo-random number generator for use by security-sensitive applications.



  • It's used as a client identifier in the message bus. Every tab has a different UUID.



  • @dkf said:

    The effective cycle time of the MT algorithm is then long enough that waiting for a predictable subsequence isn't worthwhile.

    AIUI you don't need to wait for a predictable sequence to break MT if you have access to guaranteed-successive outputs from it; collecting six hundred and something of those is enough to reconstruct the PRNG state and sync your own MT instance to the target one.



  • @accalia said:

    function (c) {
    var r = Math.random() * 16 | 0,
    v = c === 'x' ? r : (r & 0x3 | 0x8);
    return v.toString(16);
    }

    Surely that should read

    function (c) {
        return (Math.random() * (c == 'x' ? 16 : 4) ^ 8).toString(16);
    }


  • Better still:

    uuid = function () {
        return '88888888-8888-4888-2888-888888888888'.replace(/[82]/g, function(c) {
            return (Math.random()*c*2 ^ 8).toString(16);
        });
    };
    

    If you choose a language with dynamic typing and weird numerics rules, the least you can do is commit to abusing them.

    Filed under: coding with the grain


  • FoxDev

    @flabdablet said:

    Surely that should read

    <pre>function (c) {
    return (Math.random() * (c == 'x' ? 16 : 4) ^ 8).toString(16);
    }</pre>

    it did originally, but that ended up breaking the 80 character guideline and i didn't see any real benefit in adding and exception as breaking the line improved clarity for me.

    @flabdablet said:

    uuid = function () {
    return '88888888-8888-4888-2888-888888888888'.replace(/[82]/g, function(c) {
    return (Math.random()c2 ^ 8).toString(16);
    });
    };

    .... That is evil...

    bookmarked for testing with. ;-)



  • @accalia said:

    80 character guideline

    If I were working under that utterly anachronistic constraint, I'd break the lines like this:

    uuid = function () {
        return '88888888-8888-4888-2888-888888888888'.replace(/[82]/g,
            function (c) {
                return (Math.random()*c*2 ^ 8).toString(16);
            }
        );
    };

    That way I could easily come in under the 80 columns, even when indenting with the One True Tab.


  • FoxDev

    i agree that that restriction as a hard and fast rule nothing can exceed 80 characters is anachronistic

    however i find it good to use as a guideline. if my line lengths is going over 80 characters that's usually a sign i'm either nested too deep and need to split methods or 'm trying to do too much on the line.

    so i leave it in as a warning level and allow it to be overruled if i encounter a situation where can't split method/logic and any way of splitting the line hurts readability.



  • @accalia said:

    trying to do too much on the line

    or too much in a single statement is pretty much unavoidable if you're passing anonymous functions as arguments. Sometimes shortnames can make the code a little tidier:

    uuid = function () {
        return '88888888-8888-4888-2888-888888888888'.replace(/[82]/g, r);
        function r(c) {
            return (Math.random()*c*2 ^ 8).toString(16);
        }
    };

    Filed under: hurrah for declaration hoisting


  • FoxDev

    @flabdablet said:

    or too much in a single statement is pretty much unavoidable if you're passing anonymous functions as arguments.

    yep. but again that's another symptom of code smell. setting a warnig at 80 characters helps remind me of that and forces me to evaluate the code to determine it's worth. there. ;-)



  • In my capacity as an only-very-occasional Javascript coder, I'd be interested in your opinion on the stench level wafting from this thing I wrote to help with scripted MSI uninstalls on Windows. Worth tidying up, or tolerable as-is?


  • FoxDev

    ah... JScript.....

    honestly it's nto bad. and ost of what makes me cringe is unavoidable in JScript.



  • I remember being very annoyed by multiple DRY violations around setting up the WMI registry method calls that I couldn't work out any clean and concise way to eliminate. That was almost enough to make me say fuck it and do it over in VBScript, which supports WMI natively.

    Then I looked at VBScript's rather basic (heh) data manipulation facilities, decided that on balance the JScript solution would end up cleaner, and held my nose.

    At least I managed to tuck all that horror inside one global object.

    Quite pleased with unsquish() - that would have been rather nastier in VBScript.


  • FoxDev

    @flabdablet said:

    function () {
    return '88888888-8888-4888-2888-888888888888'.replace(/[82]/g, r);
    function r(c) {
    return (Math.random()c2 ^ 8).toString(16);
    }
    }

    n-n-n-n-n-necro!

    needed this for sockbot2.0 and.... well this is what i'm using. 😛

    function () {
        return '88888888-8888-4888-2888-888888888888'.replace(/[82]/g, (c) => (Math.random()*c*2 ^ 8).toString(16));
    }
    

  • FoxDev

    Lambdas rule 😄


  • FoxDev

    @RaceProUK said:

    Lambdas rule

    how did i ever do JS without them?


  • FoxDev

    @accalia said:

    how did i ever do JS without them?

    Badly 😜

    Seriously though, I find lambdas can allow you to write much cleaner code. They're especially useful as a better alternative to the myriad of one- and two-line functions you'd have to write if you didn't have them.


  • I survived the hour long Uno hand

    And with the added bonus of being a bitch and a half to debug!


  • FoxDev

    Debug tools will catch up eventually ;)


  • FoxDev

    @Yamikuronue said:

    And with the added bonus of being a bitch and a half to debug!

    there is that. there's a reason why my first debug step is usually to delambda the code in question. then fix it, then relambda it. if the last step fails roll back and leave it no lambdas.


  • FoxDev



  • You've been able to debug into those for some time, so I'm not sure what that post is on about. I know they now work in the immediate window and with edit and continue, though.



  • Not sure (c) => is better than c => would be. Other than that, I approve.

    Just to be clear, the snippet in question was released under the flabdablet licence: This is free software. Do whatever you like with it except hold me accountable for any grief it causes you.



  • Go's math/rand package doesn't even pretend to give you cryptographically secure numbers. You call rand.Intn, you get the same sequence of numbers every time unless you seed it.

    crypto/rand gives you two things: an io.Reader that gives you cryptographically secure random numbers and a set of functions that take io.Readers and return random numbers.



  • How small can you golf a type-4 UUID generator in Go, cryptographically sound or otherwise?


Log in to reply