Say you want to generate an RFC4122 version 4 compliant UUID in Javascript. Here are a few techniques. I created a test harness to test various generation methods.
Test Harness
This harness allows testing performance, validity, and collisions. It works by accepting a generator as an argument. Pretty straight forward.
var testUUIDGenerator = function(generator, iterations, testCollisions, testValidity) {
var start = new Date()
, end
, i
, uuidstore = {}
, uuid
, pattern = /[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}/
for(i = 0; i < iterations; i++) {
uuid = generator();
if(testCollisions) {
if(uuidstore[uuid])
throw 'Collision on ' + uuid;
uuidstore[uuid] = uuid;
}
if(testValidity) {
if(!uuid.match(pattern))
throw 'Invalid uuid ' + uuid;
}
}
end = new Date();
console.log((end.getTime() - start.getTime()));
}
First Attempt
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);
});
Source: Stackoverflow
Now this solution is nice but it relies on Math.random()
which is not ideal for a "random" based UUID. In fact, there are reports of collisions using this technique.
Running 100,000 iterations on my Laptop took an average of 376ms.
Second Attempt
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var nums = new Uint32Array(1)
, r
, v;
nums = window.crypto.getRandomValues(nums);
r = nums[0] % 16,
v = (c === 'x') ? r : (r&0x3|0x8);
return v.toString(16);
});
This attempts to add additional security via the crypto.getRandomValues method available in modern browsers.
Unfortunately, despite being more secure, this technique is massively slower, clocking in at 9376ms.
Third Attempt
var srng = new SecureRandom()
, uuid = ""
, bytes = new Array(16)
, i
, hex;
// get random byte array
srng.nextBytes(bytes);
// construct uuid
for(i = 0; i < bytes.length; i += 1) {
// convert byte to hex
hex = bytes[i].toString(16);
if(hex.length === 1) {
hex = "0" + hex;
}
// 12th position is a 4 signifying version 4 uuid
if(i === 6) {
uuid += "4" + hex[1];
}
// 16th position must be 8, 9, A, or B
else if (i === 8) {
uuid += (parseInt(hex[0], 16) & 0x3 | 0x8).toString(16) + hex[1];
}
// otherwise use hex character
else {
uuid += hex;
}
// insert dashes appropriately
if(i === 3 || i === 5 || i === 7 || i === 9) {
uuid += "-";
}
}
return uuid;
This technique takes advantage of SecureRandom created by Tom Wu, and is available on GitHub. This library provides secure random number generation.
Performance for this technique is on part with technique number 1.