I'm trying to obtain a random, unpredictable quite long number (± 20-25 digits) using Javascript (created by user's client) as fast and light as possible. Is this solution reliable, robust and secure enough?
When the online page is opened, the 13-digit timestamp is stored. A timer determines the number of milliseconds before user clicks on 'OK' (let's assume he got a short text to read or anything else to do). A collection of 100 invisible 'pixels' (1*1px HTML spans) is created with randomly fixed initial RGBA colors (A=0=transparency).
let d = Date.now(); // timestamp 13 digits
let n = 100 // number of 'pixels'
let pixels = ''
for (i=0; i<n; i++) {
let r = Math.floor(Math.random() * 256);
let g = Math.floor(Math.random() * 256);
let b = Math.floor(Math.random() * 256);
let c = 'rgba('+r+','+g+','+b+',0)'
pixels += '<span id="pix'+i+'" style="background-color:'+c+'"></span>'
}
Once it's done we randomly change the color of each 'pixel' every 100th of a second
let changeColor = setInterval(function(){
for (i=0; i<n; i++) {
let r = Math.floor(Math.random() * 256);
let g = Math.floor(Math.random() * 256);
let b = Math.floor(Math.random() * 256);
let c = 'rgba('+r+','+g+','+b+',0)'
document.getElementById('pix'+i).style.backgroundColor = c
}
},10);
When user clicks on 'OK' the function is stopped, a random pixel is determined and its RGB values are found
let x = Math.floor(Math.random() * n); // 39
let px = window.getComputedStyle(document.getElementById('pix'+x),null).backgroundColor
let rgb = px.match(/\d+/g); // pix 39 = [21,13,152]
Then we multiply each RGB value by x * a random factor [1 to 5]:
let r = rgb[0]*(x*Math.floor(Math.random() * 5)+1), // 21 * 39 * 2 = 1638
g = rgb[1]*(x*Math.floor(Math.random() * 5)+1), // 13 * 39 * 1 = 507
b = rgb[2]*(x*Math.floor(Math.random() * 5)+1) // 152 * 39 * 4 = 23712
By adding x + the timer + a random extract of the timestamp we obtain:
let t = Date.now()-d; // timer on click
let p = Math.floor(Math.random() * 4)+3;
let z = d.toString().substr(-p) // the xx last timestamp value (3->7)
let val = x+''+r+g+b+''+t+z // 39 1368 507 23712 1348 55601
Then we randomly shuffle the result:
function shuffle(a) {
let r = a.length, temp, rand;
while (0 !== r) {
rand = Math.floor(Math.random() * r);
r -= 1;
temp = a[r];
a[r] = a[rand];
a[rand] = temp;
}
return a; // 39136850723712134855601 -> 25851963017738613021534
}
Tests -> console
17:22:34 pix #39 = [21,13,152] 9348234523267751239843
17:22:42 pix #39 = [21,13,152] 109715237240854257137
17:23:02 pix #39 = [21,13,152] 100889146450039658553439
If we need a longer result (50, 100 digits) we can create 500 'pixels' and randomly choose 10 of them instead of one. Or add an entropy value (mouse's movement on screen : https://www.grc.com/r&d/js.htm) to the obtained value. What do you think?