Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
841 views
in Technique[技术] by (71.8m points)

javascript - How to use window.crypto.getRandomValues to get random values in a specific range

We had been using Math.random to get random numbers between 4000-64000.:

Math.floor(Math.random() * 60000 + 4000);

We have to now replace this with a more cryptographically secure random number generator. After searching on this issue we have decided to go with window.crypto.getRandomValues. I am not able to figure out how to use this to get a random number between a particular range. Can someone please help out.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

For a given min and max, the formula u cdot left ( 1 - {2^u oldsymbol{extup{mod}} (max-min) over 2^u}  ight ) sum_{i=0}^{infty} left( 2^u oldsymbol{extup{mod}} (max-min) over 2^u  ight )^i (i + 1) describes how many bits you'll use on average if you request u bits at once and retry if returning the result would introduce bias.

Fortunately, the optimal strategy is simply requesting ceil(log2(max - min + 1)) bits at once. We can only get full bytes with crypto.getRandomValues anyways, so if we have one call of crypto.getRandomValues per function call, the best we can do is:

// Generate a random integer r with equal chance in  min <= r < max.
function randrange(min, max) {
    var range = max - min;
    if (range <= 0) {
        throw new Exception('max must be larger than min');
    }
    var requestBytes = Math.ceil(Math.log2(range) / 8);
    if (!requestBytes) { // No randomness required
        return min;
    }
    var maxNum = Math.pow(256, requestBytes);
    var ar = new Uint8Array(requestBytes);

    while (true) {
        window.crypto.getRandomValues(ar);

        var val = 0;
        for (var i = 0;i < requestBytes;i++) {
            val = (val << 8) + ar[i];
        }

        if (val < maxNum - maxNum % range) {
            return min + (val % range);
        }
    }
}

If you generate many values, you may consider some optimizations, namely requesting more bytes (i.e. a larger array) in advance. If your range becomes smaller (say you want to flip a coin), than it may also be beneficial to work in a bit-based manner, i.e. request many bits upfront and then only use up the random bits you really need.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...